Mã hóa đầu cuối End-to-End bằng trong JavaScript

Thay vì lưu trữ nguyên gốc dữ liệu trên máy chủ, cách sau đây sử dụng mã hóa end-to-end, nghĩa là dữ liệu được mã hóa trước khi gửi đến máy chủ. Đảm bảo tính an toàn, không để lộ dữ liệu hay cả khi máy chủ bị tấn công xâm nhập.

Kiến trúc một trang web truyền thống.

Trong kiến ​​trúc trang web truyền thống, bạn sẽ lưu dữ liệu bằng cách gửi trực tiếp lên máy chủ, máy chủ này sẽ cung cấp cho bạn một URL có thể chia sẻ. Sau đó, người nhận tải dữ liệu xuống từ máy chủ.

Bạn tin tưởng máy chủ đã chứa thông tin của bạn. bạn cũng tin tưởng vào các đường dẫn kết nối giữa máy khách và máy chủ vì bạn sử dụng HTTPS để mã hóa dữ liệu.

mọi thứ hoạt động tốt cho đến khi máy chủ bị xâm nhập. Kẻ tấn công có quyền truy cập vào mọi dữ liệu của bạn! Đây là điều chúng tôi muốn tránh.

Mã hóa đầu cuối (End-to-End Encryption)

một số app chat hiện nay đã phổ biến mã hóa đầu cuối, một kỹ thuật cho phép nhiều máy khách khác nhau giao tiếp mà máy chủ không thể đọc nội dung giao tiếp.

Ý tưởng là mã hóa nội dung trước khi gửi đến máy chủ. Máy chủ sẽ chỉ lưu trữ nội dung đã được mã hóa và gửi lại cho máy khách.

Trong bối cảnh của một trang web, làm thế nào để phân phối khóa mà máy chủ không thể nhìn thấy. chúng ta có thể dùng hash của URL. Mọi thứ phía sau # sẽ không được gửi đến máy chủ nhưng có thể đọc được từ mã JavaScript phía máy khách.

Upload

Tạo khóa

tạo một khóa ngẫu nhiên sẽ được sử dụng để mã hóa dữ liệu.

const key = await window.crypto.subtle.generateKey(
  { name: "AES-GCM", length: 128 },
  true,
  ["encrypt", "decrypt"],
);

Mã hóa

const dataEncrypted = await window.crypto.subtle.encrypt(
  { name: "AES-GCM", iv: new Uint8Array(12) },
  key,
  new TextEncoder().encode("data content"),
);

exportKey

// chuyển key sang string để tiện gửi đi. 
const objectKey = (await window.crypto.subtle.exportKey("jwk", key)).k;
// nếu làm file server. có thể ứng dụng cách này
const url = URL + "#key=" + objectKey;
// Example: https://localhost.com/?namefile=123#key=...
// phía sau `#` sẽ không được gửi đến máy chủ

Download

importKey

const objectKey = window.location.hash.slice("#key=".length);
const key = await window.crypto.subtle.importKey(
  "jwk",
  {
    k: objectKey,
    alg: "A128GCM",
    ext: true,
    key_ops: ["encrypt", "decrypt"],
    kty: "oct",
  },
  { name: "AES-GCM", length: 128 },
  false, // extractable
  ["decrypt"],
);

Giải mã

const dataDecrypted = await window.crypto.subtle.decrypt(
  { name: "AES-GCM", iv: new Uint8Array(12) },
  key,
  dataEncrypted,
);
const decoded = new window.TextDecoder().decode(new Uint8Array(dataDecrypted));

Kết

Nếu bạn đang xây dựng một trang web cần lưu trữ dữ liệu trên máy chủ, và muốn thêm mã hóa đầu cuối, có thể thử áp dung cách này.


Tham khảo thêm:

Mã hóa End-to-End bằng Public Key (RSA) trong JavaScript