« Blog

HSTS: bật thế nào mà không tự khoá website

HSTS buộc trình duyệt luôn dùng HTTPS cho website của bạn, nhưng đặt sai có thể khiến cả tên miền con hoặc cả website không truy cập được. Bài này đưa ra lộ trình tăng max-age từng bước và cách bật trên Nginx, Apache, cPanel, DirectAdmin, Cloudflare.

HSTS làm gì

Dù website đã có HTTPS, người dùng vẫn có thể đi vào bằng http://: khi bấm một liên kết cũ dạng http://, dùng trình duyệt hay thiết bị cũ, hoặc khi kết nối HTTPS lỗi và trình duyệt quay về HTTP. Trình duyệt hiện đại thường thử HTTPS trước, nhưng khoảng hở đó vẫn đủ để kẻ đứng giữa (ví dụ ở wifi công cộng) chặn và hạ cấp kết nối. HSTS bịt khoảng hở đó.

HSTS (HTTP Strict Transport Security) là một header trả về cùng phản hồi HTTPS:

Strict-Transport-Security: max-age=31536000; includeSubDomains

Trình duyệt ghi nhớ: trong max-age giây tới, tên miền này chỉ được truy cập bằng HTTPS, kể cả khi người dùng gõ http://. Từ lúc đó, trình duyệt tự nâng lên HTTPS mà không cần hỏi máy chủ, và không cho người dùng bấm bỏ qua cảnh báo chứng chỉ.

Vì sao có thể tự khoá mình

Chính sức mạnh đó là rủi ro, vì trình duyệt của người dùng nhớ chính sách trong thời gian dài và bạn không thể thu hồi từ xa:

  • Chứng chỉ hết hạn. Bình thường người dùng còn bấm "tiếp tục truy cập". Có HSTS, họ không thể, website coi như sập cho tới khi chứng chỉ được thay. Xem bài về chứng chỉ TLS hết hạn.
  • includeSubDomains. Buộc HTTPS cho mọi tên miền con, kể cả hệ thống nội bộ cũ như crm.example.vn hay ftp.example.vn đang chỉ chạy HTTP. Chúng sẽ không truy cập được từ trình duyệt.
  • preload. Đưa tên miền vào danh sách tích hợp sẵn trong trình duyệt. Việc gỡ ra mất nhiều tháng. Chỉ làm khi thật sự chắc chắn.
  • Header chỉ có hiệu lực khi đến từ phản hồi HTTPS; trình duyệt bỏ qua nếu nhận qua HTTP.

Lộ trình tăng dần

  1. HTTPS chạy ổn mọi nơi. Mọi trang hoạt động bằng HTTPS, HTTP tự chuyển hướng 301 sang HTTPS, chứng chỉ có gia hạn tự động.
  2. Bắt đầu với max-age=300 (5 phút). Nếu có lỗi, hết 5 phút là tự khỏi.
  3. Tăng dần: 86400 (1 ngày), 604800 (1 tuần), 2592000 (30 ngày), 15552000 (180 ngày), cuối cùng 31536000 (1 năm). Mỗi bước giữ vài ngày, theo dõi lỗi.
  4. Thêm includeSubDomains sau khi liệt kê hết tên miền con (xem trong bảng DNS) và xác nhận từng cái chạy HTTPS đúng.
  5. Chỉ cân nhắc preload khi đã chạy ổn định với includeSubDomains, và đọc kỹ điều kiện tại hstspreload.org: max-age tối thiểu 31536000, có includeSubDomains và preload, HTTP chuyển hướng sang HTTPS.

Muốn rút lui: gửi max-age=0 qua HTTPS, trình duyệt sẽ xoá chính sách ở lần truy cập tiếp theo, nhưng chỉ với người dùng quay lại; phần còn lại chờ hết hạn tự nhiên.

Theo nền tảng

Nginx. Trong khối server lắng nghe cổng 443:

add_header Strict-Transport-Security "max-age=300" always;

Từ khoá always bảo đảm header cũng được gửi kèm các mã lỗi. Sau đó kiểm tra cấu hình bằng nginx -t rồi nạp lại Nginx (systemctl reload nginx).

Apache (cần mô-đun mod_headers). Trong VirtualHost cổng 443:

Header always set Strict-Transport-Security "max-age=300"

Rồi nạp lại Apache. Với hosting dùng tệp .htaccess, đặt dòng đó trong khối <IfModule mod_headers.c>.

cPanel và DirectAdmin. Mở .htaccess ở thư mục gốc của website bằng File Manager và thêm:

<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=300" env=HTTPS
</IfModule>

Chỉ thêm khi toàn bộ website đã chạy HTTPS. Nếu hosting dùng bộ nhớ đệm, xoá cache sau khi sửa. Nếu curl không thấy header (hosting sau proxy hay một số máy chủ không đặt biến HTTPS), hãy bỏ phần env=HTTPS.

Cloudflare. Không cần sửa máy chủ: vào SSL/TLS, Edge Certificates, mục HTTP Strict Transport Security (HSTS), bấm Enable HSTS và chọn thời gian tối đa, bật hay không Apply HSTS policy to subdomains và Preload tuỳ lộ trình ở trên. Mức nhỏ nhất ở Cloudflare là 1 tháng, nên không đi từ 300 giây được: muốn bắt đầu với max-age=300, hãy đặt header bằng Response Header Transform Rule (Rules, Transform Rules, Modify Response Header) rồi mới chuyển sang mục HSTS khi đã chắc chắn. Cloudflare chỉ đặt header cho các tên đi qua proxy của nó.

Cách tự kiểm tra

curl -sI https://example.vn | grep -i strict-transport
curl -sI http://example.vn | head -n 5

Dòng thứ nhất phải in ra header đã đặt. Dòng thứ hai phải cho 301 và Location: https://example.vn/. Lưu ý lệnh đầu phải gọi HTTPS; HSTS không xuất hiện trên phản hồi HTTP.

Để kiểm tra nhiều header cùng lúc, dán kết quả curl -sI https://example.vn vào công cụ đọc security header: nó cảnh báo khi max-age ngắn, khi dùng preload mà thiếu điều kiện, hoặc khi max-age=0. Dữ liệu chỉ xử lý trong trình duyệt của bạn.

Trên trình duyệt Chrome, trang chrome://net-internals/#hsts cho phép tra và xoá chính sách HSTS của một tên miền trên máy mình khi cần thử lại.

Nguồn tham khảo

  1. RFC 6797: HTTP Strict Transport Security (HSTS)
  2. MDN Web Docs: Strict-Transport-Security
  3. HSTS Preload List
  1. Content-Security-Policy và các security header cơ bản

    · 4 phút đọc

    Security header là nội quy website gửi cho trình duyệt. Bài này giải thích các header cơ bản (nosniff, frame-ancestors, Referrer-Policy, Permissions-Policy) và cách đưa CSP vào dần dần bằng chế độ Report-Only, kèm cấu hình cho Nginx, Apache, .htaccess, Cloudflare.

    #web #csp #headers

  2. Chứng chỉ TLS hết hạn: nguyên nhân và cách phòng

    · 6 phút đọc

    Chứng chỉ hết hạn là sự cố rất phổ biến nhưng phòng được gần như hoàn toàn. Bài này liệt kê các nguyên nhân thật sự hay gặp (gia hạn tự động hỏng, quên nạp lại máy chủ, email nhắc gửi nhầm người) và cách đặt giám sát bằng openssl.

    #web #tls #https