Mục tiêu học tập
- Hiểu vì sao HTTPS là bắt buộc cho mọi web app (eavesdropping, MITM, integrity)
- Nắm TLS handshake — so sánh TLS 1.2 và TLS 1.3
- Phân biệt cipher suite, key exchange (ECDHE), forward secrecy
- Hiểu certificate chain: root CA → intermediate → leaf, cách trình duyệt verify
- Biết Let's Encrypt và ACME protocol — auto-renew với certbot/Caddy
- Hiểu HSTS preload và lý do HPKP bị deprecate
- Nắm cơ bản mTLS (mutual TLS) cho service-to-service auth
1. Tại sao HTTPS bắt buộc
Ba mối đe doạ HTTPS phòng chống
Cụ thể từng mối đe doạ
| Mối đe doạ | Ví dụ thực tế | HTTPS giải quyết bằng |
|---|---|---|
| Eavesdropping | Wi-Fi công cộng nghe HTTP traffic, lấy session cookie | Encryption (symmetric cipher) |
| MITM | ISP/coffee shop chen vào, fake server response | Server authentication (certificate) |
| Tampering | ISP inject quảng cáo vào HTML, malware vào JS | Integrity (MAC/AEAD) |
Bonus: Tin cậy của user
- Browser hiển thị "Not Secure" trên HTTP → user mất niềm tin
- Một số API browser chỉ hoạt động trên HTTPS: Service Worker, WebRTC, Geolocation, Notifications, Web Crypto, HTTP/2, HTTP/3
- SEO: Google rank HTTPS site cao hơn
2. TLS handshake — TLS 1.2 vs TLS 1.3
TLS 1.2 (2008)
TLS 1.3 (2018)
Bảng so sánh
| Tính chất | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Năm ra mắt | 2008 | 2018 (RFC 8446) |
| Handshake RTT | 2 RTT | 1 RTT (0-RTT khi resume) |
| Cipher suites | ~37 suite, nhiều legacy | 5 suite, chỉ AEAD |
| Key exchange | RSA, DH, ECDHE | Chỉ (EC)DHE — forward secrecy bắt buộc |
| Forward secrecy | Optional | Mandatory |
| Legacy crypto | Cho phép RC4, 3DES, MD5, SHA-1 | Loại bỏ hoàn toàn |
| Encrypted handshake | Không (Certificate gửi plaintext) | Có (từ EncryptedExtensions trở đi) |
3. Cipher suite
Cipher suite định nghĩa các thuật toán dùng trong TLS connection.
TLS 1.2 cipher suite name
TLS 1.3 cipher suite (gọn hơn nhiều)
TLS_AES_256_GCM_SHA384 ← bulk + HKDF
TLS_CHACHA20_POLY1305_SHA256 ← cho ARM/mobile (no AES-NI)
TLS_AES_128_GCM_SHA256
Key exchange và signature không nằm trong cipher suite ở TLS 1.3 — được negotiate riêng (signature algorithm extension).
Khuyến nghị cipher (2024-2025)
GOOD (TLS 1.3):
TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
GOOD (TLS 1.2):
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-CHACHA20-POLY1305
BAD — disable:
- Anything với RC4, 3DES, DES, MD5, SHA-1, NULL
- Static RSA key exchange (no forward secrecy)
- TLS 1.0, TLS 1.1, SSL 3.0, SSL 2.0
4. Forward Secrecy
Ý tưởng
Nếu server private key bị compromise trong tương lai, traffic đã ghi lại trước đó không giải mã được.
Không có forward secrecy (RSA key exchange):
Client encrypt session key bằng server public key → gửi qua mạng
Attacker ghi lại traffic
1 năm sau: server private key bị leak
Attacker decrypt session key cũ → decrypt mọi traffic cũ
Có forward secrecy (ECDHE):
Client + Server tạo session key qua Diffie-Hellman ephemeral
Mỗi session có key pair mới, vứt đi sau handshake
Server long-term key chỉ dùng để SIGN, không encrypt session key
Server key leak → KHÔNG giúp giải mã traffic cũ
ECDHE flow đơn giản
1. Server có long-term key pair (RSA hoặc ECDSA) cho IDENTITY (sign)
2. Mỗi handshake:
- Server tạo ephemeral EC key pair (eS_priv, eS_pub)
- Client tạo ephemeral EC key pair (eC_priv, eC_pub)
- Trao đổi public key
- Cả hai compute: shared_secret = ECDH(eS_priv, eC_pub) = ECDH(eC_priv, eS_pub)
- Server SIGN ephemeral pub key bằng long-term key (chứng minh identity)
3. Sau handshake: vứt eS_priv, eC_priv → không ai có thể tái tạo shared_secret
TLS 1.3 bắt buộc forward secrecy — đây là lý do RSA key exchange bị loại bỏ hoàn toàn.
5. Certificate chain
Cấu trúc tin cậy
Browser verify như thế nào?
1. Server gửi: [leaf cert, intermediate cert] trong ServerHello
2. Browser:
a. Đọc leaf cert → kiểm tra Subject Alt Name có match hostname không
b. Kiểm tra leaf cert còn hạn (notBefore < now < notAfter)
c. Verify chữ ký của intermediate trên leaf
d. Lấy intermediate cert → verify chữ ký của root trên intermediate
e. Root cert phải có trong trust store của OS/browser
f. Kiểm tra revocation:
- CRL (Certificate Revocation List) — list bị thu hồi
- OCSP (Online Certificate Status Protocol)
- OCSP stapling — server đính kèm OCSP response
3. Nếu mọi bước OK → "Secure" lock icon
Kiểm tra chain với openssl
# Lấy certificate chain từ server
openssl s_client -connect example.com:443 -showcerts
# Verify chain
openssl s_client -connect example.com:443 -CApath /etc/ssl/certs
# In ra detail của leaf cert
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -text -noout
# Check expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -enddate -noout
# notAfter=Mar 15 23:59:59 2026 GMT
Lỗi chain phổ biến
| Lỗi | Triệu chứng | Nguyên nhân |
|---|---|---|
unable to get local issuer certificate | Browser/curl không tin cert | Server không gửi intermediate cert |
NET::ERR_CERT_DATE_INVALID | Cert hết hạn | Quên renew |
NET::ERR_CERT_COMMON_NAME_INVALID | Hostname mismatch | CN/SAN không có domain đang truy cập |
NET::ERR_CERT_AUTHORITY_INVALID | Browser không tin root | Self-signed cert hoặc root không có trong store |
6. Let's Encrypt và ACME protocol
Let's Encrypt là gì
CA miễn phí, automated, được hỗ trợ bởi Internet Security Research Group (ISRG). Cert valid 90 ngày, khuyến khích renew sau 60 ngày.
ACME protocol (RFC 8555)
certbot — cách phổ biến nhất
# Cài certbot
sudo apt install certbot python3-certbot-nginx
# Standalone (cert + nginx config auto)
sudo certbot --nginx -d example.com -d www.example.com
# DNS-01 (cho wildcard cert)
sudo certbot certonly --manual --preferred-challenges dns -d "*.example.com"
# Auto-renew (cron tự setup)
sudo certbot renew --dry-run
Cron job mặc định:
0 */12 * * * root certbot renew --quiet
Caddy — đơn giản nhất
# Caddyfile
example.com {
reverse_proxy localhost:3000
}
Đó là tất cả. Caddy tự xin Let's Encrypt cert, tự renew, tự redirect HTTP→HTTPS, tự config HTTPS đúng chuẩn. Không cần nginx + certbot dance.
nginx + certbot snippet
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
proxy_pass http://localhost:3000;
}
}
# Redirect HTTP → HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
7. HSTS và HPKP
HSTS (HTTP Strict Transport Security)
Response header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Ý nghĩa: "Browser, từ giờ trong 1 năm, chỉ kết nối với tôi qua HTTPS — kể cả khi user gõ http://".
HSTS preload list
Vấn đề first-visit: lần đầu vào site, browser chưa thấy HSTS header → có thể bị MITM trên HTTP. Giải pháp: preload list.
1. Site đăng ký tại https://hstspreload.org
2. Chrome, Firefox, Safari ship sẵn danh sách HSTS preload trong browser
3. Kể cả lần đầu vào site, browser auto upgrade HTTP→HTTPS
Yêu cầu preload:
- Cert valid
- HTTPS hoạt động trên toàn domain và subdomain
max-age >= 31536000(1 năm)includeSubDomains; preloaddirective
Cảnh báo: preload khó undo. Nếu vài tháng sau bạn muốn tắt HTTPS trên subdomain nào đó, phải đợi vài tháng để remove khỏi list.
HPKP (HTTP Public Key Pinning) — deprecated
Ý tưởng: server gửi header pin một public key. Browser nhớ pin, từ chối cert nào không match pin.
Public-Key-Pins: pin-sha256="base64=="; max-age=2592000;
Tại sao bị deprecate (2017)?
- Foot-gun lớn: pin sai key → site không truy cập được cho user đã visit, kể cả khi đã reissue cert. Một số site đã tự khoá mình hàng tháng.
- Ransomware vector: attacker compromise server tạm thời → pin key giả → server không thể recover.
- Certificate Transparency (CT) ra đời, giải quyết phần lớn vấn đề "rogue CA" mà HPKP nhắm tới.
Chrome bỏ HPKP support năm 2018. Thay thế: Expect-CT header (nay cũng deprecated) và CAA DNS record.
CAA record — phòng tuyến hiện tại
example.com. IN CAA 0 issue "letsencrypt.org"
example.com. IN CAA 0 issuewild ";"
example.com. IN CAA 0 iodef "mailto:security@example.com"
Ý nghĩa: chỉ Let's Encrypt được phép issue cert cho example.com. Mọi CA tuân thủ CA/Browser Forum baseline phải check CAA trước khi issue.
8. mTLS (mutual TLS)
TLS thường vs mTLS
TLS thường:
Client verify Server identity (qua cert)
Server không verify Client identity
→ App-level auth (cookie, JWT, OAuth) để biết client là ai
mTLS:
Client verify Server identity
Server cũng verify Client identity (qua client cert)
→ Auth ngay tại transport layer, không cần app-level token
Khi nào dùng mTLS
- Service-to-service trong microservices (vd: service mesh — Istio, Linkerd)
- B2B API giữa các công ty (cert thay vì shared secret)
- IoT — thiết bị có cert cá biệt, không phù hợp với username/password
- Zero Trust network — mọi connection phải auth, kể cả internal
Setup mTLS đơn giản với nginx
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/ssl/server.crt;
ssl_certificate_key /etc/ssl/server.key;
# Yêu cầu client cert
ssl_client_certificate /etc/ssl/ca.crt; # CA tin cậy cho client cert
ssl_verify_client on; # bắt buộc client cert
location / {
# Forward client cert info xuống upstream
proxy_set_header X-Client-CN $ssl_client_s_dn_cn;
proxy_set_header X-Client-Cert $ssl_client_escaped_cert;
proxy_pass http://backend;
}
}
Service mesh: auto mTLS
Trong Kubernetes với Istio/Linkerd:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
Istio inject sidecar (Envoy) vào mỗi pod. Sidecar handle TLS handshake với cert được cấp bởi Istio CA. App code không cần biết về TLS — Envoy lo hết.
Pattern client cert authentication trong code (Node.js)
import https from "node:https";
const options = {
hostname: "api.partner.com",
port: 443,
path: "/data",
method: "GET",
cert: fs.readFileSync("./client-cert.pem"),
key: fs.readFileSync("./client-key.pem"),
ca: fs.readFileSync("./partner-ca.pem"), // verify server
};
const req = https.request(options, (res) => {
console.log(`Status: ${res.statusCode}`);
});
req.end();
9. Câu hỏi ôn tập
-
Tại sao TLS 1.3 nhanh hơn TLS 1.2 trong handshake?
Xem đáp án
TLS 1.3 giảm từ 2 RTT xuống 1 RTT trước khi client gửi được application data, và hỗ trợ 0-RTT khi resume session. Lý do: TLS 1.3 loại bỏ negotiation 2 chiều phức tạp — client gửi
key_sharengay trong ClientHello (đoán cipher), server có đủ info để compute key và trả luôn certificate + Finished trong ServerHello. Ngoài ra, TLS 1.3 mã hoá phần lớn handshake (từ EncryptedExtensions), nâng cao privacy. -
Forward secrecy nghĩa là gì, và tại sao TLS 1.3 bắt buộc?
Xem đáp án
Forward secrecy: nếu server long-term private key bị compromise trong tương lai, traffic đã được ghi lại trước đó vẫn không giải mã được. Đạt được bằng cách dùng ephemeral Diffie-Hellman (ECDHE) — mỗi session tạo key pair tạm, vứt đi sau handshake; long-term key chỉ dùng để sign, không encrypt session key.
TLS 1.3 loại bỏ static RSA key exchange (không có forward secrecy) và chỉ cho phép (EC)DHE — vì vậy forward secrecy mặc định bật cho mọi connection.
-
Khi browser nhận được leaf certificate, nó verify như thế nào để quyết định "trusted"?
Xem đáp án
(1) Hostname đang truy cập phải match
Subject Alt Name(SAN) của cert. (2) Thời gian hiện tại nằm giữanotBeforevànotAfter. (3) Chữ ký của intermediate CA trên leaf cert valid. (4) Đi ngược chain: chữ ký của root CA trên intermediate valid. (5) Root CA phải có trong trust store của OS/browser. (6) Kiểm tra revocation qua CRL, OCSP, hoặc OCSP stapling.Nếu một trong các bước fail → browser hiển thị cảnh báo "Not Secure".
-
Vì sao HPKP bị deprecated, và cơ chế nào thay thế nó?
Xem đáp án
HPKP cho phép server pin public key vào browser — browser nhớ pin và từ chối cert nào không match. Vấn đề: (1) pin sai key = tự khoá site khỏi tất cả user đã visit, không revert được trong thời gian
max-age. (2) Attacker chiếm server tạm thời có thể pin key giả → ransomware. (3) Hiệu ứng yếu so với rủi ro vận hành.Thay thế: Certificate Transparency (CT logs — mọi cert public phải log, dễ phát hiện rogue CA) và CAA DNS record (chỉ định CA nào được phép issue cert cho domain). Cả hai đều an toàn hơn HPKP về mặt vận hành.
-
mTLS khác TLS thường ở điểm gì, và khi nào nên dùng?
Xem đáp án
TLS thường chỉ verify identity của server (qua cert). mTLS verify cả client (client cũng có cert, server check chain).
Nên dùng mTLS khi: (1) service-to-service trong microservices/service mesh — auth ở transport layer thay vì share token, (2) B2B API giữa các tổ chức — cert cấp cho từng partner, (3) IoT — thiết bị có cert cá biệt thay vì username/password, (4) Zero Trust — mọi connection nội bộ vẫn phải auth.
Trade-off: phức tạp hơn (cert lifecycle, distribution), không phù hợp cho public-facing user app (user không có client cert).
Bài tập thực hành
# 1. Kiểm tra cert của một site
openssl s_client -connect github.com:443 -servername github.com < /dev/null 2>/dev/null | \
openssl x509 -text -noout | head -30
# 2. Xem cipher suite được dùng
openssl s_client -connect github.com:443 < /dev/null 2>&1 | grep -E "Protocol|Cipher"
# 3. Test với TLS 1.3 only
openssl s_client -connect github.com:443 -tls1_3 < /dev/null
# 4. Generate self-signed cert cho local dev
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
-sha256 -days 365 -nodes \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:127.0.0.1"
# 5. Generate CA + client cert cho mTLS demo
# Tạo CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.crt -subj "/CN=My CA"
# Tạo client key + CSR
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=client-1"
# CA sign client CSR
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt -days 365
# 6. Setup Caddy với auto-HTTPS (cần domain thật + public IP)
cat > Caddyfile <<EOF
example.com {
reverse_proxy localhost:3000
}
EOF
caddy run
# 7. SSL Labs test (online, comprehensive)
# Mở: https://www.ssllabs.com/ssltest/analyze.html?d=your-site.com
# Mục tiêu: A+ rating
Tài liệu tham khảo chính thức
- TLS 1.3 RFC 8446
- Let's Encrypt — How It Works
- Mozilla SSL Configuration Generator
- SSL Labs SSL Test
- HSTS preload list
- Caddy server
- Istio mTLS
Tiếp theo: Ngày 15 — Encryption at Rest & in Transit