TCP, HTTP & Web cho Backend/TLS/HTTPS handshake — mã hoá, toàn vẹn, xác thực
23/29
Bài 23 / 29~24 phútTLS & Công cụ DebugMiễn phí lượt xem

TLS/HTTPS handshake — mã hoá, toàn vẹn, xác thực

TLS 1.3 giải quyết ba bài toán cùng lúc: mã hoá dữ liệu, đảm bảo toàn vẹn, và xác thực server. Bài này mổ cơ chế handshake 1-RTT, tại sao asymmetric chỉ dùng để trao đổi khoá, forward secrecy là gì, và đánh đổi của 0-RTT.

TL;DR: HTTPS không chỉ là "mã hoá" — TLS giải quyết ba bài toán cùng lúc: mã hoá (không ai đọc được nội dung), toàn vẹn (không ai sửa được byte giữa đường), và xác thực (đúng server bạn muốn nói chuyện). TLS 1.3 thực hiện cả ba chỉ trong 1 RTT — nhanh hơn TLS 1.2 vốn tốn 2 RTT. Cơ chế: asymmetric crypto (chậm, tốn CPU) chỉ dùng để trao đổi khoá; symmetric crypto (nhanh) dùng cho toàn bộ dữ liệu. Khoá trao đổi xong thì bỏ (ephemeral) — đây là forward secrecy: dù sau này khoá private bị lộ, các phiên cũ vẫn không giải mã được.

TLS chạy sau TCP handshake, bên trong kết nối TCP đã mở. Đây là điểm nối trực tiếp với bài TCP 3-way handshake — ba gói SYN/SYN-ACK/ACK xong rồi, TLS mới bắt đầu.

1. Analogy — Thương lượng mã hoá như chọn khoá két sắt

Hình dung bạn cần gửi tài liệu mật cho đối tác, nhưng chưa bao giờ gặp mặt và không có khoá chung:

  1. Bạn gửi cho đối tác ổ khoá mở của bạn (public key) — ai cũng thấy được, không sao.
  2. Đối tác tạo một khoá két sắt ngẫu nhiên (session key), bỏ vào hộp, khoá bằng ổ khoá của bạn, gửi lại.
  3. Chỉ bạn mới có chìa ổ khoá (private key) để mở hộp và lấy khoá két sắt.
  4. Từ đây, cả hai dùng cùng khoá két sắt để trao đổi tài liệu — nhanh, đối xứng.
Analogy két sắtTLS
Ổ khoá mở (public key)Public key trong certificate
Chìa riêng (private key)Private key server giữ bí mật
Khoá két sắt ngẫu nhiênSession key (symmetric)
Tài liệu trong kétDữ liệu HTTP được mã hoá
Kiểm tra chứng chỉ hành nghề đối tácXác thực certificate qua CA
💡 Cách nhớ asymmetric vs symmetric

Asymmetric (RSA, ECDH): hai khoá khác nhau, chậm, dùng để trao đổi khoá an toàn. Symmetric (AES-GCM): một khoá, nhanh gấp 100-1000 lần, dùng để mã hoá dữ liệu thật. TLS kết hợp hai loại: asymmetric mở đường, symmetric làm việc.

2. Ba bài toán TLS giải quyết

HTTPS không chỉ là "mã hoá dữ liệu". TLS giải quyết ba bài toán riêng biệt mà thiếu bất kỳ cái nào cũng nguy hiểm:

🔒 Mã hoá (Confidentiality)
Dữ liệu bị mã hoá — router giữa đường, ISP, hay kẻ nghe lén đều không đọc được nội dung.
🔏 Toàn vẹn (Integrity)
Mỗi record TLS có MAC (Message Authentication Code) — bất kỳ byte nào bị sửa giữa đường, bên nhận phát hiện ngay và huỷ kết nối.
✅ Xác thực (Authentication)
Server chứng minh danh tính qua certificate được CA ký — bạn biết đang nói chuyện đúng server, không phải kẻ giả mạo.
⚠️ Thiếu xác thực thì mã hoá vô nghĩa

Nếu không xác thực server, bạn có thể thiết lập kênh mã hoá hoàn hảo — nhưng với kẻ tấn công đứng giữa (Man-in-the-Middle). Kẻ đó forward lại mọi request của bạn tới server thật, nhưng nó đọc được tất cả. Mã hoá tốt đến đâu cũng vô nghĩa khi sai đối tượng.

3. TLS 1.3 handshake — cơ chế 1-RTT

TLS 1.3 (RFC 8446, 2018) rút gọn handshake xuống còn 1 RTT bằng cách gửi key share ngay trong ClientHello thay vì chờ server confirm cipher suite trước.

sequenceDiagram
    participant C as Client
    participant S as Server
    Note over C,S: TCP da ESTABLISHED (3-way handshake xong)
    C->>S: ClientHello (TLS versions, cipher suites, key share)
    S-->>C: ServerHello (chosen cipher, key share)<br/>+ Certificate + CertificateVerify + Finished
    Note over C,S: Ca hai tinh duoc session key tu day
    C->>S: Finished
    Note over C,S: TLS ESTABLISHED — HTTP bat dau

Bước 1 — ClientHello (client gửi): Client gửi một gói chứa: (a) danh sách phiên bản TLS client hỗ trợ, (b) danh sách cipher suite ưa thích, (c) key share — phần public của Diffie-Hellman ephemeral key pair mà client vừa tạo. Gửi key share ngay từ đầu là điểm mấu chốt làm TLS 1.3 chỉ cần 1 RTT.

Bước 2 — ServerHello + Certificate + Finished (server gửi, cùng một lần bay): Server chọn cipher suite, gửi lại key share của nó (cũng ephemeral DH). Từ hai key share này, cả hai phía độc lập tính ra cùng session key mà không truyền key qua mạng — đây là phép màu của Diffie-Hellman. Server cũng gửi certificate (chứa public key và danh tính), chữ ký xác nhận nó giữ private key tương ứng, và Finished để đóng phần server của handshake.

Bước 3 — Finished (client gửi): Client xác minh certificate (xem bài 02), xác nhận server Finished hợp lệ, rồi gửi Finished của mình. Từ đây kết nối ESTABLISHED — HTTP request đầu tiên có thể đi kèm luôn gói này.

Tổng cộng: 1 RTT từ ClientHello tới khi HTTP bắt đầu. Mọi dữ liệu sau đó được mã hoá bằng AES-256-GCM (symmetric, nhanh).

4. TLS 1.2 vs 1.3 — tại sao 1 RTT quan trọng

TLS 1.2 — 2 RTT
ClientHello
↓↑ RTT 1
ServerHello + Cert
↓ client tính key
ClientKeyExchange + Finished
↓↑ RTT 2
Server Finished → HTTP
TLS 1.3 — 1 RTT
ClientHello + key share
↓↑ RTT 1
ServerHello + key share
+ Cert + Finished
↓ client Finished
HTTP bat dau

Với RTT trong nước ~20ms, 1 RTT tiết kiệm được 20ms mỗi kết nối mới. Xuyên lục địa RTT 150ms, tiết kiệm 150ms — gần như người dùng cảm nhận được. Trên hệ thống tải cao với hàng triệu kết nối mới mỗi giờ, đây là con số không nhỏ.

TLS 1.2 cũng bị loại bỏ nhiều cipher suite yếu (RSA key exchange không forward secrecy, RC4, 3DES). TLS 1.3 chỉ còn lại các cipher suite mạnh — không còn đường tắt cho kẻ tấn công.

5. Forward secrecy — bảo vệ quá khứ

Forward secrecy (hay Perfect Forward Secrecy — PFS) là tính chất: dù private key của server bị lộ sau này, kẻ tấn công vẫn không giải mã được các phiên cũ đã bị bắt.

Cơ chế: TLS 1.3 bắt buộc dùng ephemeral Diffie-Hellman (ECDHE). Với mỗi phiên kết nối, client và server tạo một cặp khoá DH mới và tạm thời (ephemeral). Session key được tính từ cặp khoá này. Sau khi phiên kết thúc, cặp khoá tạm bị xoá — không lưu ở đâu cả.

Hệ quả: kẻ tấn công ghi lại traffic HTTPS hôm nay với hi vọng sau này lấy được private key của server → vô ích. Session key đã không còn tồn tại.

TLS 1.2 cho phép dùng RSA key exchange không ephemeral — session key được mã hoá bằng public key của server và gửi trực tiếp qua mạng. Ai có private key server là giải mã được mọi phiên cũ. Đây là lý do TLS 1.3 bỏ hoàn toàn RSA key exchange.

6. Session resumption và 0-RTT

Sau khi kết nối TLS đã thiết lập một lần, client và server có thể tái dùng phiên mà không phải chạy lại toàn bộ handshake.

Session resumption (1-RTT): Server cấp cho client một session ticket mã hoá. Lần sau client gửi ticket này kèm ClientHello, server giải mã lấy lại session state và bỏ qua handshake đầy đủ. Vẫn tốn 1 RTT nhưng không phải tính lại key share.

0-RTT Early Data: TLS 1.3 cho phép client gửi dữ liệu ứng dụng ngay trong lần đi đầu tiên (cùng ClientHello), không cần chờ server xác nhận handshake. Giảm xuống còn 0 RTT cho dữ liệu đầu tiên.

⚠️ 0-RTT có nguy cơ replay attack

0-RTT Early Data không có forward secrecydễ bị replay. Kẻ tấn công chặn gói 0-RTT và gửi lại (replay) — server nhận lần thứ hai và xử lý. Nếu request đó là "POST /checkout", server charge hai lần. Chỉ dùng 0-RTT cho request idempotent (GET, HEAD) và chỉ khi server có cơ chế chống replay (nonce, timestamp window).

7. Pitfall — hiểu nhầm thường gặp

Nhầm 1: "TCP handshake và TLS handshake là một thứ." ✅ Hai handshake riêng biệt, nối tiếp nhau. TCP (SYN/SYN-ACK/ACK) mở kết nối tầng Transport — xảy ra cho cả http:// lẫn https://. TLS chạy sau đó, bên trong kết nối TCP đã mở, chỉ với https://. Trong tcpdump bạn thấy 3 gói TCP trước, rồi mới tới ClientHello. Nhầm hai cái khiến bạn debug sai chặng.

Nhầm 2: "HTTPS chậm hơn HTTP vì phải mã hoá." ✅ Chi phí mã hoá dữ liệu bằng AES-GCM trên CPU hiện đại là không đáng kể (phần cứng có AES-NI). Chi phí thật là handshake (1 RTT) — nhưng nó bị loại bỏ gần hết nhờ keep-alive và session resumption. Đổi lại, HTTP/2 chỉ chạy trên HTTPS và thường làm trang nhanh hơn HTTP/1.1 thuần nhờ multiplexing.

Nhầm 3: "0-RTT an toàn, dùng được cho mọi request." ✅ 0-RTT Early Data thiếu forward secrecy và dễ bị replay. Chỉ an toàn cho GET/HEAD — không dùng cho POST có side effect. Nhiều framework mặc định không bật 0-RTT đúng lý do này.

8. Liên hệ các bài khác

9. 📚 Deep Dive — tài liệu gốc

📚 RFC & spec chính thức

Đọc khi muốn đi tới tận gốc:

Ghi chú thực hành: openssl s_client -connect google.com:443 -tls1_3 để bắt TLS 1.3 handshake thật. curl --tlsv1.3 -v https://google.com -o /dev/null in chi tiết từng bước.

10. Tóm tắt

  • TLS giải quyết ba bài toán: mã hoá (confidentiality), toàn vẹn (integrity), xác thực (authentication) — thiếu bất kỳ cái nào là không đủ an toàn.
  • Asymmetric crypto (ECDH) chỉ dùng để trao đổi khoá — chậm nhưng an toàn qua mạng. Symmetric (AES-GCM) dùng cho toàn bộ dữ liệu — nhanh.
  • TLS 1.3 hoàn thành handshake trong 1 RTT (TLS 1.2 tốn 2 RTT) bằng cách gửi key share ngay trong ClientHello.
  • Ephemeral DH (ECDHE) bắt buộc trong TLS 1.3 — mỗi phiên có khoá riêng, không lưu lại → forward secrecy: phiên cũ không bị giải mã dù sau này private key bị lộ.
  • Session resumption tái dùng phiên cũ qua session ticket (vẫn 1 RTT). 0-RTT gửi dữ liệu ngay trong ClientHello nhưng dễ bị replay — chỉ dùng cho idempotent request.
  • TLS chạy sau TCP handshake, trước HTTP — nhầm thứ tự là debug sai chặng.

11. Tự kiểm tra

Tự kiểm tra
Q1
TLS giải quyết ba bài toán gì? Tại sao thiếu xác thực thì mã hoá trở nên vô nghĩa?
TLS đồng thời đảm bảo: mã hoá (nội dung không đọc được), toàn vẹn (dữ liệu không bị sửa giữa đường — phát hiện qua MAC), và xác thực (server chứng minh danh tính qua certificate). Thiếu xác thực, bạn có thể thiết lập kênh mã hoá hoàn hảo nhưng với kẻ tấn công đứng giữa — kẻ đó đọc được mọi thứ rồi forward lại server thật. Mã hoá tốt đến đâu cũng vô nghĩa khi sai đối tượng.
Q2
Tại sao TLS dùng asymmetric crypto để trao đổi khoá nhưng lại dùng symmetric crypto cho dữ liệu thật?
Asymmetric crypto (RSA, ECDH) cho phép trao đổi thông tin mà không cần khoá chung từ trước — hai bên chưa gặp nhau vẫn thiết lập được session key an toàn. Tuy nhiên asymmetric chậm hơn symmetric đến 100-1000 lần do tính toán toán học phức tạp. Vì vậy TLS dùng asymmetric để trao đổi session key (1 lần, nhỏ), rồi symmetric (AES-GCM) cho toàn bộ dữ liệu — tận dụng ưu điểm của cả hai: an toàn khi thiết lập, nhanh khi truyền.
Q3
TLS 1.3 nhanh hơn TLS 1.2 ở điểm nào cụ thể? Kỹ thuật gì cho phép điều đó?
TLS 1.2 tốn 2 RTT: RTT 1 để thống nhất cipher suite và server gửi cert, RTT 2 để client gửi key exchange rồi cả hai Finished. TLS 1.3 chỉ tốn 1 RTT: client gửi kèm key share (phần public của ephemeral DH key pair) ngay trong ClientHello — server nhận được là tính ra session key ngay, gửi lại key share + cert + Finished trong một lần. Client xác minh xong gửi Finished. Tiết kiệm được 1 RTT (20ms trong nước, 150ms+ xuyên lục địa) mỗi kết nối mới.
Q4
Forward secrecy là gì? Tại sao TLS 1.2 với RSA key exchange không có tính chất này?
Forward secrecy (PFS) nghĩa là: dù sau này private key của server bị lộ, các phiên cũ đã ghi lại vẫn không giải mã được. TLS 1.3 dùng ephemeral ECDH — mỗi phiên tạo cặp khoá DH mới, tính session key từ đó, rồi xoá khoá ephemeral. Session key không tồn tại nơi nào khác. TLS 1.2 với RSA key exchange thì client mã hoá session key bằng public key server rồi gửi qua mạng — ai có private key server là giải mã được session key, từ đó giải mã toàn bộ traffic đã ghi. Đây chính là lý do TLS 1.3 bỏ hoàn toàn RSA key exchange.
Q5
0-RTT Early Data có rủi ro gì? Loại request nào an toàn để dùng 0-RTT?
0-RTT Early Data không có forward secrecy (dùng lại session ticket từ phiên cũ, không tạo khoá ephemeral mới) và dễ bị replay attack: kẻ tấn công ghi lại gói 0-RTT và gửi lại sau — server nhận và xử lý lần thứ hai như request hợp lệ. Nếu request đó là POST /transfer-money hay POST /checkout, hậu quả rõ ràng. Chỉ an toàn dùng 0-RTT cho request idempotent (GET, HEAD) mà gửi lại nhiều lần không có side effect, và khi server có cơ chế chống replay (timestamp window, nonce). Nhiều framework vì vậy mặc định không bật 0-RTT.
Q6
Bạn chạy curl -v https://example.com và thấy 'TLS handshake, Done' xuất hiện sau 'Connected'. Điều đó cho biết gì về thứ tự các chặng?
Connected xác nhận TCP ESTABLISHED (3-way handshake SYN/SYN-ACK/ACK xong). TLS handshake, Done xác nhận TLS handshake hoàn thành — chạy sau TCP, bên trong kết nối TCP đã mở. Chỉ sau dòng đó, HTTP request mới được gửi. Thứ tự bất biến: TCP → TLS → HTTP. Nếu TLS handshake fail (cert hết hạn, sai tên miền), bạn thấy lỗi ngay sau Connected, trước khi HTTP bắt đầu — và đó là nơi debug, không phải lỗi HTTP 4xx/5xx.
Q7
Tại sao HTTPS không làm chậm trang web nhiều như người ta hay nghĩ?
Có hai chi phí riêng: (1) Mã hoá dữ liệu bằng AES-GCM — CPU hiện đại có lệnh AES-NI phần cứng, chi phí này gần như 0. (2) Handshake (1 RTT với TLS 1.3) — đây là chi phí thật, nhưng bị loại bỏ gần hết nhờ keep-alive (tái dùng kết nối, không handshake lại) và session resumption. Đổi lại, HTTPS bắt buộc để dùng HTTP/2 — protocol này multiplexing nhiều request trên một kết nối, thường làm trang nhanh hơn HTTP/1.1 rõ rệt. Kết quả thực tế: HTTPS không chậm hơn HTTP đáng kể, và thường nhanh hơn nhờ HTTP/2.

Bài tiếp theo: Certificate & CA — vì sao trình duyệt tin một server

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên

Bài tiếp theo

Certificate & CA — vì sao trình duyệt tin một server