🎯 什么是 HSTS?
HSTS = HTTP Strict Transport Security(HTTP 严格传输安全)
核心作用: 强制浏览器只能通过 HTTPS 访问网站,彻底杜绝 HTTP 连接。
🤔 为什么需要 HSTS?
问题场景
即使网站支持 HTTPS,用户仍可能遇到这些问题:
场景 1:用户输入习惯 👤
用户输入:example.com
浏览器首次访问:http://example.com
然后重定向到:https://example.com
问题: 第一次请求是 HTTP(明文),可能被劫持!
场景 2:链接问题 🔗
网页中的链接:<a href="http://example.com/login">登录</a>
点击后:走 HTTP 协议
问题: 敏感数据可能泄露!
场景 3:中间人攻击 😈
用户 → http://bank.com → 黑客 → 钓鱼网站
(明文请求被拦截)
问题: SSL Strip 攻击,降级到 HTTP
HSTS 如何解决?
第一次访问(HTTPS):
服务器响应头:Strict-Transport-Security: max-age=31536000
浏览器记住:
"未来一年内,example.com 只能用 HTTPS!"
后续访问:
用户输入 http://example.com
浏览器自动改为 https://example.com(不发送HTTP请求!)
📝 HSTS 响应头详解
基本语法
Strict-Transport-Security: max-age=<秒数>; includeSubDomains; preload
参数说明
1️⃣ max-age(必需)
Strict-Transport-Security: max-age=31536000
单位:秒
31536000= 1 年63072000= 2 年(推荐)在此期间,浏览器强制使用 HTTPS
生命周期:
第一次访问 → 记录HSTS策略 → 倒计时开始
每次访问 → 刷新倒计时 → 重新开始
超过max-age → HSTS失效 → 可以访问HTTP
2️⃣ includeSubDomains(可选)
Strict-Transport-Security: max-age=31536000; includeSubDomains
作用: HSTS 策略也应用到所有子域名
示例:
设置在:example.com
同时保护:
- example.com
- www.example.com
- api.example.com
- *.example.com
⚠️ 注意: 确保所有子域名都支持 HTTPS,否则会无法访问!
3️⃣ preload(可选)
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
作用: 允许网站加入浏览器的 HSTS 预加载列表
这是最强防护!下面详细讲解。
🎪 HSTS Preload List(预加载列表)
什么是预加载?
传统 HSTS 的问题:
首次访问仍需 HTTP → 存在风险窗口
Preload 的解决方案:
网站提交到预加载列表
↓
浏览器内置该列表
↓
用户从未访问过该网站
↓
浏览器已知必须用 HTTPS!
预加载列表特点
✅ 优点:
首次访问就受保护
无风险窗口
Chrome、Firefox、Safari、Edge 等主流浏览器共享
⚠️ 代价:
一旦提交,很难移除(至少数月)
必须满足严格条件
所有子域名必须支持 HTTPS
提交要求
要加入预加载列表,网站必须:
✅ 使用有效的 HTTPS 证书
✅ 所有 HTTP 流量重定向到 HTTPS
✅ 所有子域名支持 HTTPS
✅ 响应头设置:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
✅ max-age 至少 1 年(推荐 2 年)
提交地址: https://hstspreload.org/
🔧 配置示例
Nginx 配置
server {
listen 443 ssl http2;
server_name example.com;
# SSL 证书配置
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# HSTS 配置
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 其他配置...
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
Apache 配置
<VirtualHost *:443>
ServerName example.com
# SSL 配置
SSLEngine on
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/key.pem
# HSTS 配置
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</VirtualHost>
# HTTP 重定向
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
Node.js (Express) 配置
const express = require('express');
const helmet = require('helmet');
const app = express();
// 使用 helmet 中间件设置 HSTS
app.use(helmet.hsts({
maxAge: 63072000, // 2年
includeSubDomains: true,
preload: true
}));
// 或手动设置
app.use((req, res, next) => {
res.setHeader(
'Strict-Transport-Security',
'max-age=63072000; includeSubDomains; preload'
);
next();
});
🔍 浏览器如何处理 HSTS
Chrome 查看 HSTS 状态
访问:chrome://net-internals/#hsts
可以进行的操作:
🔍 Query(查询):查看某个域名的 HSTS 状态
➕ Add(添加):手动添加 HSTS 域名(测试用)
❌ Delete(删除):删除 HSTS 记录(清除缓存)
Firefox 查看
打开开发者工具(F12)
切换到 "网络" 标签
查看响应头中的
Strict-Transport-Security
🎭 实际运作流程
首次访问(未启用 Preload)
步骤1: 用户输入 example.com
↓
步骤2: 浏览器访问 http://example.com
↓
步骤3: 服务器返回 301 重定向到 https://example.com
↓
步骤4: 浏览器访问 https://example.com
↓
步骤5: 服务器返回响应 + HSTS 头
↓
步骤6: 浏览器记录 HSTS 策略
⚠️ 风险窗口: 步骤 2 的 HTTP 请求可能被劫持
后续访问(HSTS 生效)
步骤1: 用户输入 http://example.com
↓
步骤2: 浏览器检查 HSTS 缓存 ✓
↓
步骤3: 浏览器内部升级为 https://example.com
↓
步骤4: 直接发送 HTTPS 请求(跳过HTTP!)
✅ 无风险: 根本不发送 HTTP 请求
启用 Preload 后
步骤1: 用户首次访问 example.com
↓
步骤2: 浏览器检查内置 Preload 列表 ✓
↓
步骤3: 直接使用 HTTPS
🎯 完美: 从来没有 HTTP 请求!
⚠️ 常见问题与注意事项
1. 部署前的准备工作
检查清单:
☑ 所有资源都支持 HTTPS(图片、CSS、JS)
☑ 所有子域名都配置了证书
☑ 确认没有硬编码的 HTTP 链接
☑ 测试环境验证无误
2. 渐进式部署策略
阶段1: 测试期(1周)
max-age=604800 // 7天
阶段2: 短期(1个月)
max-age=2592000 // 30天
阶段3: 长期(1年)
max-age=31536000 // 1年
阶段4: 加入 Preload(2年)
max-age=63072000; includeSubDomains; preload
3. 错误配置的后果
❌ 问题场景:
# 设置了 includeSubDomains
Strict-Transport-Security: max-age=31536000; includeSubDomains
# 但 sub.example.com 没有配置 HTTPS
结果: sub.example.com 完全无法访问!
解决方法:
浏览器端:
chrome://net-internals/#hsts删除记录服务器端:设置
max-age=0取消 HSTS
Strict-Transport-Security: max-age=0
4. 从 Preload 列表移除
如果需要移除(极少情况):
在 hstspreload.org 提交移除请求
等待数月(浏览器更新周期)
在此期间必须维护 HTTPS
⏰ 时间成本: 3-12 个月
🛡️ HSTS 与其他安全措施
安全组合拳
HSTS → 强制 HTTPS
+
CSP → 内容安全策略
+
HPKP (已废弃) → 公钥固定
+
Cookie Secure → Cookie 仅 HTTPS 传输
+
SameSite → 防止 CSRF
完整的安全响应头示例
# HSTS
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
# 防止点击劫持
X-Frame-Options: DENY
# 防止 MIME 类型嗅探
X-Content-Type-Options: nosniff
# XSS 保护
X-XSS-Protection: 1; mode=block
# CSP
Content-Security-Policy: default-src https:; script-src 'self'
# Cookie 安全
Set-Cookie: session=xxx; Secure; HttpOnly; SameSite=Strict
📊 HSTS 统计
当前使用情况:
🌐 超过 20% 的 Alexa Top 100 万网站启用 HSTS
📈 Preload 列表包含 10 万 + 域名
🏆 Google、Facebook、Twitter 等大厂全部启用
🎓 总结
HSTS 的三个等级
级别1: 基础 HSTS
max-age=31536000
级别2: 包含子域名
max-age=31536000; includeSubDomains
级别3: 预加载(最安全)
max-age=63072000; includeSubDomains; preload
一句话记忆
HSTS 让浏览器记住 "这个网站只能用 HTTPS",从此用户再也不会走不安全的 HTTP,即使他自己手动输入
http://!
🚀 最佳实践建议
✅ 从小的
max-age开始测试✅ 确认所有子域名都支持 HTTPS 再加
includeSubDomains✅ 充分测试后再考虑
preload✅ 监控证书过期时间
✅ 配合 301/302 重定向使用