Hướng dẫn end-to-end encryption javascript - javascript mã hóa đầu cuối

Khi truyền hoặc lưu trữ dữ liệu người dùng, đặc biệt là các cuộc hội thoại riêng tư, điều cần thiết là phải xem xét sử dụng các kỹ thuật mật mã để đảm bảo quyền riêng tư.

Bằng cách đọc hướng dẫn này, bạn sẽ học cách mã hóa dữ liệu mã hóa đầu cuối trong các ứng dụng web không sử dụng gì ngoài JavaScript và API Crypto Web, đây là API trình duyệt gốc.

Xin lưu ý rằng hướng dẫn này là rất cơ bản và giáo dục nghiêm ngặt, có thể chứa đơn giản hóa và không nên thực hiện giao thức mã hóa của riêng bạn là không nên. Các thuật toán được sử dụng có thể chứa một số 'gotchas' nhất định nếu không được sử dụng đúng với sự trợ giúp của các chuyên gia bảo mật

Bạn cũng có thể tìm thấy dự án đầy đủ trong repo GitHub này nếu bạn bị lạc. Và nếu bạn có bất kỳ câu hỏi nào, vui lòng liên hệ với tôi trên Twitter :).

Mã hóa từ đầu đến cuối là gì?

Mã hóa từ đầu đến cuối là một hệ thống truyền thông nơi những người duy nhất có thể đọc tin nhắn là những người giao tiếp. Không có người nghe lén có thể truy cập vào các khóa mật mã cần thiết để giải mã cuộc trò chuyện, thậm chí không phải là một công ty điều hành dịch vụ nhắn tin.

  • Hacker Lexicon: Mã hóa từ đầu đến cuối là gì

API tiền điện tử web là gì?

API mật mã web xác định giao diện cấp thấp để tương tác với vật liệu khóa mật mã được quản lý hoặc phơi bày bởi các tác nhân người dùng. Bản thân API là bất khả tri về việc triển khai lưu trữ chính cơ bản nhưng cung cấp một bộ giao diện chung cho phép các ứng dụng web phong phú thực hiện các hoạt động như tạo và xác minh chữ ký, băm và xác minh, mã hóa và giải mã, mà không cần truy cập vào vật liệu khóa thô thô .

  • W3C: API mật mã web

Lên những điều cơ bản

Trong các bước sau, chúng tôi sẽ khai báo các chức năng thiết yếu liên quan đến mã hóa từ đầu đến cuối. Bạn có thể sao chép từng cái vào tệp .js chuyên dụng trong thư mục lib. Lưu ý rằng tất cả chúng là các chức năng async do bản chất không đồng bộ của API của Crypto.

Lưu ý: Không phải tất cả các trình duyệt đều thực hiện các thuật toán chúng tôi sẽ sử dụng. Cụ thể, Internet Explorer và Microsoft Edge. Kiểm tra bảng khả năng tương thích tại MDN Web Docs: API Crypto - Web tinh tế.

Tạo một cặp khóa

Các cặp khóa mật mã là điều cần thiết để mã hóa từ đầu đến cuối. Một cặp khóa bao gồm một khóa công khai và khóa riêng. Mỗi người dùng trong ứng dụng của bạn phải có một cặp khóa để bảo vệ dữ liệu của họ, với thành phần công khai có sẵn cho người dùng khác và thành phần riêng tư chỉ có thể truy cập vào chủ sở hữu của cặp khóa. Bạn sẽ hiểu làm thế nào những thứ này phát huy tác dụng trong phần tiếp theo.key pair consists of a public key and a private key. Each user in your application should have a key pair to protect their data, with the public component available to other users and the private component only accessible to the key pair's owner. You'll understand how these come into play in the next section.

Để tạo cặp khóa, chúng tôi sẽ sử dụng phương thức window.crypto.subtle.generateKey và xuất các khóa riêng và công khai bằng cách sử dụng window.crypto.subtle.exportKey với định dạng JWK. Cái sau là cần thiết để lưu hoặc truyền các phím này. Hãy nghĩ về nó như một cách để tuần tự hóa các khóa để sử dụng bên ngoài JavaScript.

Ngoài ra, tôi đã chọn thuật toán ECDH với đường cong hình elip P-256 vì nó được hỗ trợ tốt và sự cân bằng phù hợp giữa bảo mật và hiệu suất. Ưu tiên này có thể thay đổi theo thời gian khi các thuật toán mới có sẵn.

Khóa rút ra

Chúng tôi sẽ sử dụng cặp khóa được tạo trong bước cuối cùng để rút ra khóa mật mã đối xứng mã hóa và giải mã dữ liệu và là duy nhất cho bất kỳ hai người dùng giao tiếp nào. Ví dụ: người dùng A có được khóa bằng khóa riêng của họ với khóa công khai của người dùng B và người dùng B có cùng một khóa bằng khóa riêng và khóa công khai của người dùng A của họ. Không ai có thể tạo khóa dẫn xuất mà không có quyền truy cập vào ít nhất một trong các khóa riêng của người dùng, vì vậy điều cần thiết là giữ chúng an toàn.derived key without access to at least one of the users' private keys, so it's essential to keep them safe.

Trong bước trước, chúng tôi đã xuất cặp khóa theo định dạng JWK. Trước khi chúng tôi có thể lấy phím, chúng tôi cần nhập những người đó trở lại trạng thái ban đầu bằng cách sử dụng window.crypto.subtle.importKey. Để lấy phím, chúng tôi sẽ sử dụng window.crypto.subtle.deriveKey.

Trong trường hợp này, tôi đã chọn thuật toán AES-GCM cho số dư bảo mật/hiệu suất đã biết và tính khả dụng của trình duyệt.

Mã hóa văn bản

Bây giờ chúng ta có thể sử dụng khóa dẫn xuất để mã hóa văn bản, vì vậy an toàn để truyền nó.encrypt text, so it's safe to transmit it.

Trước khi mã hóa, chúng tôi mã hóa văn bản thành Uint8Array, vì đó là những gì hàm mã hóa. Chúng tôi mã hóa mảng đó bằng cách sử dụng window.crypto.subtle.encrypt, và sau đó chúng tôi chuyển đầu ra ArrayBuffer của nó trở lại Uint8Array, sau đó chúng tôi chuyển sang lib1 và mã hóa nó thành base64. JavaScript làm cho nó hơi phức tạp, nhưng đây chỉ là một cách để biến dữ liệu được mã hóa của chúng tôi thành văn bản có thể truyền.

Như bạn có thể thấy, tham số thuật toán AES-GCM bao gồm một vectơ khởi tạo (IV). Đối với mọi hoạt động mã hóa, nó phải là ngẫu nhiên và khác nhau để đảm bảo sức mạnh của mã hóa. Nó được bao gồm trong thông báo để nó có thể được sử dụng trong quá trình giải mã, đó là bước tiếp theo.

Decrypt văn bản

Bây giờ chúng ta có thể sử dụng khóa dẫn xuất để giải mã bất kỳ văn bản được mã hóa nào chúng ta nhận được, thực hiện chính xác so với bước mã hóa.decrypt any encrypted text we receive, doing precisely the opposite from the encrypt step.

Trước khi giải mã, chúng tôi truy xuất vectơ khởi tạo, chuyển đổi chuỗi trở lại từ base64, biến nó thành Uint8Array và giải mã nó bằng định nghĩa thuật toán tương tự. Sau đó, chúng tôi giải mã ArrayBuffer và trả về chuỗi có thể đọc được của con người.

Cũng có thể quá trình giải mã này sẽ thất bại do sử dụng khóa hoặc vectơ khởi tạo sai, điều đó có nghĩa là người dùng không có cặp khóa chính xác để giải mã văn bản họ nhận được. Trong trường hợp như vậy, chúng tôi trả về một thông báo lỗi.

Tích hợp trong ứng dụng trò chuyện của bạn

Và đó là tất cả các công việc mật mã cần thiết! Trong các phần sau, tôi sẽ giải thích cách tôi sử dụng các phương thức chúng tôi đã triển khai ở trên để mã hóa từ đầu đến cuối một ứng dụng trò chuyện được xây dựng với các thành phần trò chuyện phản ứng mạnh mẽ của Stream Chat.

Sao chép dự án

Sao chép kho lưu trữ-Chat được mã hóa trong một thư mục cục bộ, cài đặt các phụ thuộc và chạy nó.

Sau đó, một tab trình duyệt nên mở. Nhưng trước tiên, chúng ta cần định cấu hình dự án với khóa API Chat Chat của riêng mình.

Định cấu hình bảng điều khiển trò chuyện luồng

Tạo tài khoản của bạn tại getStream.io, tạo một ứng dụng và chọn phát triển thay vì sản xuất.

Screenshot of a user creating a development application at GetStream.io

Để đơn giản hóa, hãy tắt cả kiểm tra AUTH và kiểm tra quyền. Hãy chắc chắn để nhấn Lưu. Khi ứng dụng của bạn đang được sản xuất, bạn nên giữ những thứ này được bật và có phần phụ trợ để cung cấp mã thông báo cho người dùng.

Screenshot of skip auth checks and permission enabled in a Stream App dashboard

Để tham khảo trong tương lai, xem tài liệu về xác thực và tài liệu về quyền.

Vui lòng lưu ý thông tin đăng nhập luồng, vì chúng tôi sẽ sử dụng chúng để khởi tạo ứng dụng trò chuyện trong ứng dụng trong bước tiếp theo. Vì chúng tôi đã vô hiệu hóa xác thực và quyền, chúng tôi sẽ chỉ thực sự cần chìa khóa ngay bây giờ. Tuy nhiên, trong tương lai, bạn sẽ sử dụng bí mật trong phần phụ trợ của mình để thực hiện xác thực để phát hành mã thông báo của người dùng để trò chuyện luồng, vì vậy ứng dụng trò chuyện của bạn có thể có các điều khiển truy cập phù hợp.

Screenshot of credentials on stream dashboard

Như bạn có thể thấy, tôi đã điều chỉnh lại các phím của mình. Sẽ là tốt nhất nếu bạn giữ các thông tin này an toàn.

Thay đổi thông tin đăng nhập

Trong lib4, thay đổi khóa với của bạn. Chúng tôi sẽ sử dụng đối tượng này để thực hiện các cuộc gọi API và định cấu hình các thành phần trò chuyện.

Sau này, bạn sẽ có thể kiểm tra ứng dụng. Trong các bước sau, bạn sẽ hiểu nơi các chức năng chúng tôi xác định phù hợp.

Đặt người dùng

Trong lib5, chúng tôi xác định chức năng đặt người dùng của máy khách trò chuyện và cập nhật nó bằng khóa công khai của cặp khóa đã cho. Gửi khóa công khai là cần thiết cho người dùng khác để lấy khóa cần thiết để mã hóa và giải mã giao tiếp với người dùng của chúng tôi.

Trong chức năng này, chúng tôi nhập lib6 được xác định trong bước trước. Nó lấy ID người dùng và một cặp khóa, sau đó gọi lib7 để đặt người dùng. Sau đó, nó kiểm tra xem người dùng đó đã có khóa công khai hay không và nếu nó khớp với khóa công khai trong cặp khóa được đưa ra. Nếu khóa công khai phù hợp hoặc không tồn tại, chúng tôi cập nhật người dùng đó với khóa công khai đã cho; Nếu không, chúng tôi ngắt kết nối và hiển thị lỗi.key pair, then it calls lib7 to set the user. After that, it checks whether that user already has a public key and if it matches the public key in the key pair given. If the public key matches or is non-existent, we update that user with the given public key; if not, we disconnect and display an error.

Thành phần người gửi

Trong lib8, chúng tôi xác định màn hình đầu tiên, trong đó chúng tôi chọn ID người dùng của mình và có thể tạo một cặp khóa bằng hàm chúng tôi mô tả trong lib9 hoặc, nếu đây là người dùng hiện có, hãy dán cặp khóa được tạo tại thời điểm tạo người dùng .

Image shows a login form with an id field, a key pair field,  a generate button, and a submit button

Thành phần người nhận

Trong async0, chúng tôi xác định màn hình thứ hai, trong đó chúng tôi chọn ID của người dùng mà chúng tôi muốn giao tiếp. Thành phần sẽ tìm nạp người dùng này với async1. Kết quả của cuộc gọi đó sẽ chứa khóa công khai của người dùng, chúng tôi sẽ sử dụng để lấy khóa mã hóa/giải mã.

Image shows a form with a field for the user id you want to communicate with and a submit button

Thành phần KeyDeriver

Trong async2, chúng tôi xác định màn hình thứ ba, trong đó khóa được lấy bằng phương thức chúng tôi đã triển khai trong async3 với khóa riêng của người gửi (Hoa Kỳ) và khóa công khai của người nhận. Thành phần này chỉ đơn thuần là một màn hình tải thụ động vì thông tin cần thiết được thu thập trong hai màn hình trước đó. Nhưng nó sẽ hiển thị lỗi nếu có vấn đề với các khóa.

Thành phần mã hóa

Trong async4, chúng tôi tùy chỉnh thành phần thông báo của Chat Chat để giải mã thông báo bằng phương thức chúng tôi xác định trong async5 cùng với dữ liệu được mã hóa và khóa dẫn xuất.

Image shows a chat message saying This is an encrypted message

Nếu không có sự tùy chỉnh này của thành phần tin nhắn, nó sẽ hiển thị như thế này:

Image shows a chat message with unintelligible text

Việc tùy chỉnh được thực hiện bằng cách gói thành phần async6 của Chat Chat và sử dụng móc async7 để sửa đổi prop thông báo với phương thức giải mã.

Thành phần EncryptedMessageInput

Trong async8, chúng tôi tùy chỉnh thành phần thông báo của Chat Chat để mã hóa thông báo được viết trước khi gửi nó bằng phương thức mà chúng tôi đã xác định trong async9 cùng với văn bản gốc.

Tùy chỉnh được thực hiện bằng cách gói thành phần ____3030 của Stream Chat và cài đặt window.crypto.subtle.generateKey1 Prop thành một hàm mã hóa văn bản trước khi gửi đến kênh.

Thành phần trò chuyện

Và cuối cùng, vào window.crypto.subtle.generateKey2, chúng tôi xây dựng toàn bộ màn hình trò chuyện bằng các thành phần của Stream Chat và các thành phần thông điệp tùy chỉnh và EncryptedMessageInput của chúng tôi.

Thành phần window.crypto.subtle.generateKey3 có prop window.crypto.subtle.generateKey4, được đặt thành thành phần window.crypto.subtle.generateKey5 tùy chỉnh và window.crypto.subtle.generateKey6 chỉ có thể được đặt ngay bên dưới nó trong hệ thống phân cấp.

Các bước tiếp theo với API Web Crypto

Xin chúc mừng!Bạn vừa học cách thực hiện mã hóa từ đầu đến cuối cơ bản trong các ứng dụng web của bạn.Điều quan trọng là phải biết đây là hình thức mã hóa đầu cuối cơ bản nhất.Nó thiếu một số điều chỉnh bổ sung có thể làm cho nó chống đạn hơn cho thế giới thực, chẳng hạn như đệm ngẫu nhiên, chữ ký kỹ thuật số và bí mật về phía trước, trong số những người khác.Ngoài ra, để sử dụng trong thế giới thực, điều quan trọng là có được sự giúp đỡ của các chuyên gia bảo mật ứng dụng.