Cách thiết lập HSTS mà không tự khóa mình bên ngoài
Một kế hoạch triển khai theo giai đoạn, có thể đảo ngược cho Strict-Transport-Security, giúp cải thiện quyền riêng tư mà không biến một chứng chỉ lỗi thành sự cố ngừng hoạt động.
Mục lục
- HSTS đơn giản cho đến khi không còn đơn giản
- Header HSTS thực sự làm gì
- Các kịch bản khóa ngoài cần tránh
- 1. Một subdomain bị lãng quên chưa sẵn sàng cho HTTPS
- 2. Chứng chỉ hết hạn
- 3. Staging hoặc công cụ nội bộ nằm dưới domain production
- 4. Preload được xem như một checkbox thường lệ
- Một kế hoạch triển khai an toàn
- Step 1: Kiểm tra mọi hostname bạn kiểm soát
- Step 2: Sửa HTTPS trước khi thêm HSTS
- Step 3: Bắt đầu với max-age rất ngắn
- Step 4: Tăng dần
- Step 5: Chỉ thêm includeSubDomains sau khi audit là thực chất
- Step 6: Xem preload như một dự án riêng
- Ví dụ cấu hình
- Nginx
- Apache
- CDN hoặc edge platform
- Cách hoàn tác HSTS an toàn
- Checklist kiểm thử trước khi phát hành
- Lý do quyền riêng tư cho HSTS
HSTS đơn giản cho đến khi không còn đơn giản
HTTP Strict Transport Security, thường được viết tắt là HSTS, nói với trình duyệt: “với trang này, luôn dùng HTTPS.” Khi trình duyệt nhận được header qua một kết nối HTTPS hợp lệ, nó sẽ ghi nhớ quy tắc đó trong khoảng thời gian bạn chỉ định.
Điều đó hữu ích. Nó ngăn các cuộc tấn công hạ cấp giao thức, giảm các yêu cầu không an toàn do vô tình, và tránh khoảnh khắc khó xử khi người dùng gõ example.com rồi chạm vào HTTP thuần trong chốc lát trước khi được chuyển hướng.
Nó cũng rất “dính”. Nếu bạn công bố sai chính sách HSTS, trình duyệt có thể tiếp tục thực thi chính sách đó rất lâu sau khi bạn đã gỡ header khỏi máy chủ. Đó là cách các nhóm tự khóa mình bên ngoài: không hẳn là khỏi bảng quản trị của chính họ, mà khỏi trình duyệt của người dùng, subdomain, hệ thống staging, endpoint cũ, và các dịch vụ bị lãng quên chưa sẵn sàng cho HTTPS bắt buộc.
Mục tiêu không phải là tránh HSTS. Mục tiêu là triển khai nó như một cuộc di trú, không phải như một công tắc bật/tắt.
Header HSTS thực sự làm gì
Một header HSTS điển hình trông như sau:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Nó có ba phần quan trọng:
max-age: trong bao lâu, tính bằng giây, trình duyệt nên bắt buộc dùng HTTPS cho host này.includeSubDomains: quy tắc có áp dụng cho mọi subdomain hay không.preload: tín hiệu cho biết bạn muốn domain được đưa vào danh sách preload của trình duyệt.
Trình duyệt chỉ tin header này khi nhận được nó qua HTTPS hợp lệ. Nếu chứng chỉ không hợp lệ, hết hạn, hoặc không khớp, trình duyệt không nên chấp nhận chính sách HSTS mới từ phản hồi đó.
Khi chính sách đã được lưu, các lần truy cập sau tới http://example.com sẽ được trình duyệt nâng cấp thành https://example.com trước khi yêu cầu được gửi đi. Đó là lợi ích về quyền riêng tư: yêu cầu không an toàn không bao giờ rời khỏi thiết bị.
Các kịch bản khóa ngoài cần tránh
Hầu hết lỗi HSTS không bắt nguồn từ website chính. Chúng xảy ra ở vùng rìa.
1. Một subdomain bị lãng quên chưa sẵn sàng cho HTTPS
includeSubDomains nghe có vẻ gọn gàng, nhưng nó tuyệt đối. Nếu bạn đặt nó trên example.com, nó áp dụng cho:
www.example.comapi.example.comold-crm.example.comprinter-setup.example.comstaging.example.com- bất kỳ thứ gì khác bên dưới domain đó
Nếu bất kỳ host nào trong số đó không thể phục vụ HTTPS hợp lệ, người dùng đã cache chính sách HSTS sẽ không thể truy cập chúng qua HTTP.
2. Chứng chỉ hết hạn
Khi không có HSTS, đôi khi người dùng bấm bỏ qua cảnh báo chứng chỉ. Đó không phải là thực hành bảo mật tốt, nhưng vẫn xảy ra.
Với HSTS, các trình duyệt hiện đại không cho phép dễ dàng bỏ qua lỗi chứng chỉ đối với host đó. Đây chính là mục đích. Điều đó cũng có nghĩa là việc gia hạn chứng chỉ cần phải nhàm chán, được giám sát, và được kiểm thử.
3. Staging hoặc công cụ nội bộ nằm dưới domain production
Đặt công cụ nội bộ dưới *.example.com có thể trở nên phiền toái khi domain cha dùng includeSubDomains. Nếu các công cụ đó dùng chứng chỉ tự ký, certificate authority riêng, cấu hình TLS cũ, hoặc hoàn toàn không có HTTPS, HSTS sẽ phơi bày lối tắt này.
Đây là một lý do khiến nhiều nhóm giữ hệ thống nội bộ và thử nghiệm dưới một domain riêng có chính sách bảo mật riêng.
4. Preload được xem như một checkbox thường lệ
HSTS preload không chỉ là một directive khác. Nó có nghĩa là domain của bạn có thể được đóng gói sẵn trong trình duyệt dưới dạng chỉ-HTTPS trước khi bất kỳ người dùng nào từng truy cập trang của bạn.
Điều đó đóng khoảng trống “lần truy cập đầu tiên”, nhưng khó đảo ngược hơn nhiều. Việc gỡ khỏi danh sách preload có thể mất vài tuần hoặc vài tháng mới đến được người dùng, tùy theo chu kỳ phát hành của trình duyệt. Preload phù hợp với các domain ổn định, trưởng thành. Nó không phù hợp với một site vẫn đang khám phá danh mục subdomain của mình.
Một kế hoạch triển khai an toàn
Step 1: Kiểm tra mọi hostname bạn kiểm soát
Trước khi đặt includeSubDomains, hãy liệt kê mọi hostname bên dưới domain. Bản ghi DNS là điểm khởi đầu, nhưng không phải toàn bộ câu chuyện. Hãy kiểm tra cấu hình CDN, dashboard hosting, hostname liên quan đến email, công cụ marketing cũ, storage bucket, và tài liệu nội bộ.
Với mỗi hostname, hãy trả lời:
- Nó phục vụ HTTP, HTTPS, hay cả hai?
- Chứng chỉ HTTPS có hợp lệ và được gia hạn tự động không?
- Nó có chuyển hướng HTTP sang HTTPS sạch sẽ không?
- Nó có được dự định công khai không?
- Nó còn cần thiết không?
Nếu nhóm của bạn đã có thói quen debug header production, việc này sẽ nằm tự nhiên bên cạnh các bước kiểm tra redirect và header. Chúng tôi đã đề cập quy trình đó trong một bộ công cụ nhỏ để debug redirect và HTTP header trong production.
Step 2: Sửa HTTPS trước khi thêm HSTS
HSTS không làm cho một thiết lập HTTPS hỏng trở nên an toàn. Nó chỉ làm cho HTTPS trở thành bắt buộc.
Trước khi bật nó, hãy xác minh:
- Chứng chỉ TLS bao phủ đúng hostname.
- Chứng chỉ được gia hạn tự động.
- HTTP chuyển hướng sang HTTPS bằng một bước nhảy sạch duy nhất khi có thể.
- Chuyển hướng host canonical nhất quán, ví dụ từ non-
wwwsangwww, hoặc ngược lại. - Asset của ứng dụng không phụ thuộc vào URL
http://không an toàn.
Mixed content ít phổ biến hơn trước đây, nhưng vẫn xuất hiện trong theme CMS cũ, snippet analytics, media nhúng, và đường dẫn ảnh được hard-code.
Step 3: Bắt đầu với max-age rất ngắn
Đừng bắt đầu bằng một năm. Hãy bắt đầu bằng năm phút:
Strict-Transport-Security: max-age=300
Chỉ triển khai điều đó trên hostname bạn đang kiểm thử, thường là website production canonical. Tạm thời bỏ qua includeSubDomains.
Sau đó kiểm thử trong trình duyệt thật và bằng yêu cầu dòng lệnh:
curl -I https://example.com
Bạn nên thấy đúng một header Strict-Transport-Security. Header HSTS bị lặp từ app server và CDN là nguồn gây nhầm lẫn phổ biến. Trình duyệt thường áp dụng chính sách hiệu lực, nhưng con người đang debug sự cố không cần thêm sự mơ hồ.
Step 4: Tăng dần
Nếu không có gì hỏng, hãy tăng thời lượng theo từng giai đoạn:
Strict-Transport-Security: max-age=86400
Sau đó:
Strict-Transport-Security: max-age=604800
Rồi có thể là:
Strict-Transport-Security: max-age=2592000
Một lịch trình thực tế là:
- 5 phút
- 1 ngày
- 1 tuần
- 1 tháng
- 6 tháng hoặc 1 năm
Không có phần thưởng nào cho việc vội vàng. Toàn bộ ý nghĩa của triển khai theo giai đoạn là cho monitoring, hộp thư hỗ trợ, và các trường hợp biên có thời gian để nói cho bạn biết checklist của bạn đã bỏ sót gì.
Step 5: Chỉ thêm includeSubDomains sau khi audit là thực chất
Khi mọi subdomain công khai đã sẵn sàng cho HTTPS, bạn có thể cân nhắc:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Đây là thời điểm cần thận trọng. Nếu một dịch vụ legacy vẫn cần HTTP, đừng thêm includeSubDomains vào domain cha. Hoặc di trú dịch vụ đó, chuyển nó sang domain khác, hoặc chấp nhận rằng chính sách HSTS của bạn hiện tại phải hẹp hơn.
Security header nên phản ánh thực tế. Chúng không nên được dùng như những tấm poster truyền động lực cho hạ tầng mà bạn hy vọng sẽ có sau này.
Step 6: Xem preload như một dự án riêng
Chỉ cân nhắc preload khi tất cả điều sau là đúng:
- Domain và tất cả subdomain hỗ trợ HTTPS hợp lệ.
- HTTP chuyển hướng sang HTTPS.
- Header HSTS dùng
max-ageít nhất 31536000 giây. - Header bao gồm
includeSubDomains. - Header bao gồm
preload. - Bạn tự tin rằng sẽ không cần HTTP thuần ở bất kỳ đâu bên dưới domain.
Một header sẵn sàng cho preload trông như sau:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Gửi vào danh sách preload là một cam kết dài hạn. Nếu site là microsite chiến dịch, domain sản phẩm tạm thời, hoặc domain có ranh giới sở hữu chưa rõ, hãy bỏ qua.
Ví dụ cấu hình
Nginx
Dùng always để header cũng được gửi trên các phản hồi lỗi:
add_header Strict-Transport-Security "max-age=300" always;
Sau khi triển khai ổn định:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Apache
Khi đã bật mod_headers:
Header always set Strict-Transport-Security "max-age=300"
Về sau:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
CDN hoặc edge platform
Nếu CDN của bạn đặt response header, hãy ưu tiên quản lý HSTS ở một nơi. Đừng đặt một chính sách ở origin và một chính sách khác ở edge trừ khi bạn có lý do rất rõ ràng.
Cũng hãy kiểm tra liệu CDN có áp dụng header cho redirect, lỗi được cache, và trang lỗi tùy chỉnh hay không. Một site production không chỉ là phản hồi 200 OK của nó.
Cách hoàn tác HSTS an toàn
Nếu bạn cần tắt HSTS, hãy gửi:
Strict-Transport-Security: max-age=0
Nhưng có một điểm vướng: trình duyệt phải truy cập thành công site qua HTTPS hợp lệ để nhận header đó. Nếu bản thân HTTPS bị hỏng, người dùng có chính sách HSTS đã cache không thể lấy chỉ dẫn sẽ xóa nó.
Vì vậy thứ tự khôi phục thông thường là:
- Khôi phục HTTPS hợp lệ.
- Phục vụ
Strict-Transport-Security: max-age=0. - Giữ nó đủ lâu để người dùng quay lại nhận được.
- Gỡ hoặc thay thế header sau khi sự cố được giải quyết.
Nếu domain được preload, việc phục vụ max-age=0 là chưa đủ đối với hồ sơ trình duyệt mới. Bạn cũng cần yêu cầu gỡ khỏi danh sách preload và chờ thay đổi đó được phát hành qua các bản cập nhật trình duyệt.
Checklist kiểm thử trước khi phát hành
Hãy dùng checklist này trước khi tăng max-age hoặc thêm includeSubDomains:
- URL HTTPS canonical trả về chứng chỉ hợp lệ.
- HTTP chuyển hướng sang HTTPS.
- Chỉ có một header HSTS.
- Header xuất hiện trên redirect và phản hồi lỗi khi phù hợp.
- Tất cả subdomain công khai có HTTPS hợp lệ.
- Việc gia hạn chứng chỉ được giám sát.
- Không có hệ thống nội bộ trọng yếu nào phụ thuộc vào HTTP dưới cùng domain cha.
- Preload đã được thảo luận rõ ràng, không được thêm theo thói quen.
Lighthouse cũng có thể gắn cờ security header bị thiếu hoặc yếu trong một số ngữ cảnh, nhưng đó không nên là phương pháp xác minh duy nhất của bạn. Nếu bạn dùng nó như một phần của đánh giá rộng hơn, hãy đọc các phát hiện như tín hiệu thay vì phán quyết; cùng tư duy đó cũng áp dụng khi bạn đọc báo cáo Lighthouse mà không hoảng loạn.
<!-- tool-cta:start -->
💡 Hãy thử cách này: Trước và sau mỗi thay đổi HSTS, hãy kiểm tra phản hồi Strict-Transport-Security bằng Get Headers để xác nhận rằng max-age, includeSubDomains và preload đúng như bạn mong đợi.
<!-- tool-cta:end -->
Lý do quyền riêng tư cho HSTS
HSTS thường được mô tả như một security header, và đúng là vậy. Nó cũng có lợi ích về quyền riêng tư: nó giảm khả năng yêu cầu đầu tiên của người dùng bị rò rỉ qua HTTP thuần trên một mạng không đáng tin cậy.
Điều đó quan trọng trên Wi-Fi sân bay, mạng khách sạn, mạng khách doanh nghiệp, và bất kỳ nơi nào lưu lượng của người dùng có thể bị quan sát hoặc sửa đổi. Một yêu cầu HTTP thuần có thể lộ hostname, path, cookie không có cờ Secure, và các chi tiết yêu cầu khác. HTTPS không phải phép màu, nhưng việc bắt buộc nó một cách nhất quán sẽ loại bỏ cả một lớp rò rỉ có thể tránh được.
Những triển khai HSTS tốt nhất là những triển khai không có gì đáng chú ý. Chúng được triển khai chậm rãi, được chống lưng bởi chứng chỉ đáng tin cậy, và nhàm chán đến mức không ai để ý. Đó chính xác là điều bạn muốn từ một header mà chế độ lỗi của nó có thể rất kịch tính.