Một lớp handshake mã hoá trên nền TLS — và vì sao tôi tự xây
TLS vốn đã mã hoá lưu lượng khi truyền. Vậy tại sao còn bọc payload đăng ký/đăng nhập trong một lớp mã hoá nữa? Không phải vì TLS yếu — mà vì một lớp envelope ở tầng ứng dụng thể hiện vài tính chất đáng được làm chủ một cách tường minh, và nó làm cho ranh giới tin cậy hiện rõ ngay trong code.
Lược đồ
Mỗi request sinh một cặp khoá ECDH tạm thời mới ở phía client. Client thực hiện ECDH với khoá công khai mà server công bố, đưa shared secret qua HKDF-SHA256 để dẫn ra khoá 256-bit, rồi mã hoá payload JSON bằng AES-256-GCM.
{
"v": 1,
"epk": "<client ephemeral public key>",
"iv": "...",
"ct": "...",
"ts": 1733400000000,
"nonce": "..."
}
Vì cặp khoá là tạm thời theo từng request, một khoá server dài hạn bị lộ cũng không giải mã được lưu lượng cũ đã bị bắt trên đường truyền. Đó là forward secrecy, ở mức từng thông điệp.
Chống replay là bắt buộc
Một envelope bị bắt lại không được phép phát lại. Hai cơ chế xử lý việc này:
- Từ chối mọi request có
tsnằm ngoài cửa sổ ±60 giây. - Lưu
noncevào Redis với TTL bằng đúng cửa sổ đó; một nonce lặp lại sẽ bị từ chối.
Cả ts lẫn nonce đều được gắn vào additional authenticated data của AES-GCM, nên không thể bị sửa mà không làm hỏng xác thực.
Nó không thay thế cái gì
Đây là phòng thủ theo chiều sâu, không phải vật thay thế TLS. TLS vẫn kết thúc ở biên. Handshake là một bảo đảm ở tầng ứng dụng xếp chồng lên trên — và thành thật mà nói, là một minh chứng rõ ràng cho chủ đích kỹ thuật bảo mật.
Phần hiện thực nằm trong workspace package dùng chung packages/crypto, để client và server dùng một bản hiện thực duy nhất, không lệch nhau giữa mã hoá và giải mã.
Bình luận
Chưa có bình luận nào. Hãy là người đầu tiên.