HTTP và Web sâu: hiểu giao thức từ dây cáp lên

Sê-ri mổ xẻ HTTP, TLS và web server bằng công cụ thật (curl, openssl, nginx) — mỗi bài một demo đo được.

18/18 phần đã đăng Web
1 Một request HTTP đi qua dây cáp: thực ra chỉ là text gõ đúng khuôn trên TCP Nhiều người dùng HTTP mỗi ngày qua thư viện mà chưa từng thấy một request thô trông thế nào. Sự thật đơn giản đến bất ngờ: HTTP là vài dòng text kết thúc bằng CRLF, gửi qua một socket TCP. Bài này xem thô bằng curl --trace-ascii, rồi tự gõ tay một request bằng socket Python không dùng thư viện HTTP nào — và server vẫn trả lời. 22/09/2026 · 5 phút đọc 2 Ba header HTTP quyết định: Host, Content-Type, và Content-Length vs chunked Vì sao hàng nghìn website chung một địa chỉ IP vẫn phân biệt được nhau? Vì sao có response biết trước độ dài, có response gửi theo từng khúc? Bài này đo thật ba header cốt lõi: Host cho virtual hosting, Content-Type quyết client hiểu body thế nào, và cặp loại trừ Content-Length vs Transfer-Encoding chunked — xem tận byte khung chunk. 22/09/2026 · 5 phút đọc 3 Mã trạng thái và redirect HTTP: 301 vs 302 vs 307/308, và bẫy đổi POST thành GET Ai cũng biết 404 và 500, nhưng khác biệt thật giữa 301 và 302, giữa 307 và 308 thì nhiều người mơ hồ. Điểm mấu chốt không chỉ là vĩnh viễn hay tạm thời — mà là có giữ nguyên phương thức POST hay không. Bài này đo thật: 301/302 âm thầm đổi POST thành GET, 307/308 giữ nguyên, và một vòng lặp redirect dừng ở đâu. 22/09/2026 · 6 phút đọc 4 HTTP keep-alive: vì sao mở lại kết nối cho mỗi request là lãng phí — đo thật Trước khi gửi được một byte dữ liệu, mỗi kết nối mới phải trả giá: tra DNS, bắt tay TCP ba bước, rồi bắt tay TLS. Keep-alive giữ kết nối mở để tái dùng. Bài này đo thật: một handshake tốn ~69ms tới byte đầu, 6 request keep-alive dùng 1 kết nối thay vì 6, và 300 request tái dùng nhanh gấp ~19 lần so với mở mới mỗi lần. 22/09/2026 · 6 phút đọc 5 HTTP/1.1 vs HTTP/2: multiplexing nhiều luồng trên một kết nối — đo thật HTTP/1.1 gửi request tuần tự trên mỗi kết nối, nên response chậm chặn hết phần sau (head-of-line blocking) — trình duyệt phải mở tới 6 kết nối để lách. HTTP/2 chia message thành frame nhị phân, đan xen nhiều luồng trên một kết nối. Bài này đo thật bằng nginx và curl: thương lượng giao thức, log server xác nhận, và multiplexing nhanh hơn khi tải nhiều tài nguyên. 22/09/2026 · 6 phút đọc 6 Cache HTTP: Cache-Control, ETag và cú 304 Not Modified — đo thật Cache HTTP có hai cơ chế tách bạch mà nhiều người trộn lẫn: hết hạn (Cache-Control/max-age — client không hỏi server chút nào) và xác thực lại (ETag/Last-Modified — client hỏi còn mới không, server đáp 304 nếu chưa đổi). Bài này đo thật bằng nginx và curl: một request có điều kiện trả 304 không body, và ETag đổi khi nội dung đổi. 22/09/2026 · 5 phút đọc 7 Cookie và session: cách web nhớ bạn, và ba thuộc tính chặn tấn công HTTP không có trạng thái — mỗi request độc lập, server không tự biết ai gửi. Cookie là cách vá: server gửi Set-Cookie, client tự gửi lại ở mọi request sau. Bài này đo thật luồng session bằng curl, và mổ ba thuộc tính bảo mật sống còn: HttpOnly chống XSS trộm cookie, Secure buộc HTTPS, SameSite chống CSRF. 22/09/2026 · 5 phút đọc 8 Nén nội dung HTTP: gzip vs brotli vs zstd — đo tỉ lệ nén thật Một trang HTML 224 KB có thể xuống còn 16 KB trên đường truyền mà người dùng không hề hay biết. Cơ chế: client mời (Accept-Encoding), server chọn (Content-Encoding), nén trong suốt hai đầu. Bài này đo thật tỉ lệ nén của gzip, brotli, zstd trên một trang HTML thật, và xem nginx thương lượng nén qua HTTP. 22/09/2026 · 5 phút đọc 9 TLS handshake từng bước: xem tận mắt bằng openssl s_client Trước khi một byte HTTPS chạy, client và server làm một cuộc bắt tay TLS: thỏa thuận phiên bản, chọn cipher, trao khóa tạm, và server chứng minh danh tính bằng chứng chỉ. Bài này dùng openssl s_client -msg để xem từng handshake message thật của TLS 1.3 (ClientHello, ServerHello, Certificate, Finished), so TLS 1.3 với 1.2, và đọc chuỗi chứng chỉ. 22/09/2026 · 5 phút đọc 10 Chứng chỉ X.509 và chuỗi tin cậy: vì sao trình duyệt tin server — tự dựng CA để hiểu Cái ổ khóa xanh trên trình duyệt dựa trên một chuỗi tin cậy: cert của site được một CA ký, CA đó lại được CA gốc ký, và trình duyệt chỉ tin sẵn vài CA gốc. Bài này tự dựng một CA rồi ký cert cho web.local bằng openssl, đọc cấu trúc cert (subject, issuer, SAN, hạn), và chứng minh xác thực chuỗi thành công với CA đúng, thất bại với CA sai. 22/09/2026 · 6 phút đọc 11 Nginx reverse proxy: một cửa trước nhiều backend — đo round-robin và X-Forwarded Reverse proxy đứng trước các server, thay mặt chúng trả lời client: cân bằng tải, kết thúc TLS, gom nhiều service sau một tên miền. Bài này dựng nginx proxy tới 3 backend, đo round-robin chia đúng 10/10/10 trên 30 request, và giải thích vì sao thiếu header X-Forwarded-* làm backend thấy sai IP và giao thức của client. 22/09/2026 · 5 phút đọc 12 Nginx phục vụ tĩnh và tối ưu hiệu năng: sendfile, cache, và đo bằng ab Nginx phục vụ file tĩnh nhanh đến mức nào? Bài cuối sê-ri đo thật: sendfile (zero-copy) cho thông lượng ~281 MB/s và 4301 request/giây trên file 68KB, Cache-Control để trình duyệt khỏi tải lại, gzip nén 156 KB xuống 1.2 KB. Kèm một cái bẫy đo lường: ab mặc định HTTP/1.0 nên không nhận gzip — phải đo tỉ lệ nén bằng curl. 22/09/2026 · 6 phút đọc 13 HTTP/3 và QUIC: vì sao web bỏ TCP sang UDP — và điều nó sửa mà HTTP/2 không HTTP/2 multiplex nhiều luồng trên một kết nối TCP, nhưng mất một gói TCP là mọi luồng bị giữ lại (TCP head-of-line blocking). HTTP/3 chạy trên QUIC (UDP) để mỗi luồng độc lập ở tầng vận chuyển. Bài này đo thật: curl lab không có h3 (báo trung thực), site thật quảng cáo h3 qua Alt-Svc, và chi phí bắt tay TCP+TLS hai vòng mà QUIC gộp còn một. 22/09/2026 · 5 phút đọc 14 CORS không phải bảo mật server: hiểu cross-origin qua preflight và header thật Nhiều người tưởng CORS bảo vệ server, hoặc cứ thấy lỗi CORS là tại backend chặn. Thực ra CORS là cơ chế của TRÌNH DUYỆT: same-origin policy chặn JS đọc chéo origin, còn server chủ động mở qua header Access-Control-Allow-*. Bài này dựng server thật chỉ cho một origin, đo preflight OPTIONS, và chứng minh origin lạ vẫn nhận 200 nhưng bị trình duyệt chặn. 22/09/2026 · 7 phút đọc 15 Xác thực HTTP: Basic, Bearer và API key — ai giữ bí mật, ai chỉ mã hoá kiểu Base64 Nhiều người tưởng Basic auth 'mã hoá' mật khẩu vì thấy chuỗi Base64 lạ mắt. Thực ra Base64 giải ngược được trong một lệnh. Bài này dựng server thật cho cả ba scheme — Basic, Bearer token, API key — đo bằng curl: thử thách 401 WWW-Authenticate, token bị sửa một ký tự thành invalid_token, và giải ngược Base64 lộ nguyên mật khẩu. 22/09/2026 · 6 phút đọc 16 Range request: cách tua video, tải tiếp file dở và tải song song hoạt động Vì sao kéo thanh tua video nhảy ngay tới giữa phim mà không tải lại từ đầu? Vì sao tải file 2GB đứt mạng rồi nối tiếp được? Câu trả lời là Range request. Bài này dựng nginx thật phục vụ một file, đo bằng curl: 206 Partial Content, Content-Range, suffix range, lỗi 416, và ghép hai phần lại md5 khớp file gốc. 22/09/2026 · 5 phút đọc 17 WebSocket: HTTP nâng cấp thành kênh hai chiều — mổ xẻ cái bắt tay 101 WebSocket không phải một giao thức tách rời HTTP mà mọc lên TỪ HTTP: một request GET với header Upgrade, đáp lại là 101 Switching Protocols chứ không phải 200. Bài này tự dựng cả server lẫn client WebSocket bằng socket thuần, đo output thật: cách tính Sec-WebSocket-Accept từ key + GUID, và frame hai chiều mà frame từ client bắt buộc mask. 22/09/2026 · 6 phút đọc 18 Header bảo mật HTTP: HSTS, CSP, X-Frame-Options — mỗi dòng chặn một kiểu tấn công Một dòng header có thể chặn cả một lớp tấn công. Bài này xem các header bảo mật THẬT mà chính blog này gửi, rồi dùng Chromium thật nhúng hai iframe — một trang có X-Frame-Options DENY, một không — để thấy trình duyệt thực sự từ chối hiển thị trang DENY: 'Refused to display ... X-Frame-Options to deny'. Không phải mô tả, là trình duyệt thi hành. 22/09/2026 · 6 phút đọc