🔒 第05章 · OCSP/HSTS/安全头
security headers 加固
OCSP、HSTS 与安全响应头¶
这一章讲 HTTPS 站点"证书之外"的那层安全:如何让浏览器更快更安全地验证你的证书、如何强制全站走 HTTPS、以及通过响应头把常见的客户端攻击面压到最小。学完你就能像一台生产网站那样把 Nginx 的"安全头"配齐。
为什么证书配好了还不够¶
证书解决了"加密与身份",但还有几个问题:
- 吊销状态检查:证书可能被吊销(密钥泄露等),浏览器需要确认它是否仍有效。这就是 OCSP / CRL 的作用。
- 降级攻击:用户访问
http://时可能被中间人劫持或降级成明文传输。需要 HSTS 强制浏览器永远用 HTTPS。 - 客户端攻击:XSS、点击劫持、MIME 嗅探、中间人注入第三方脚本——都需要响应头来防御。
OCSP Stapling(证书状态缓存)¶
在线证书状态协议(OCSP)是浏览器向 CA 查询证书是否被吊销。每次连接都查会很慢,而且泄露访问习惯。OCSP Stapling 由服务器定时向 CA 拉取一个"签名的状态快照",并在 TLS 握手里主动发给浏览器,又快又省。
Nginx 里开启:
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.53 valid=30s; # 用本机 DNS 解析 CA 地址,别用已停服的 8.8.8.8
验证是否生效:
# 检查握手是否携带 stapled response
openssl s_client -connect learn.bangdream.xyz:443 -status -servername learn.bangdream.xyz 2>/dev/null | grep -A2 'OCSP response:'
# 应看到 OCSP Response Status: successful (0x0)
HSTS(HTTP Strict Transport Security)¶
告诉浏览器:"此域接下来 一定 用 HTTPS,别允许降级到 http"。加了它,以后即使你忘了输 https://,浏览器也会自动用 HTTPS;而且能防范 SSL stripping 攻击。
# 在 443 的 server block 里加:max-age 指缓存秒数,includeSubDomains 覆盖子域,preload 申请进浏览器预加载名单
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
注意 | 一旦开 HSTS,浏览器就不会再允许 http 访问。务必确认你的整站(含所有子域、资源)都已支持 HTTPS 再启用
includeSubDomains;特别是还没配证书的子域会被直接判死。建议先只开max-age观察一段时间,再加includeSubDomains。
关键安全响应头一览¶
| 响应头 | 作用 | 推荐值 |
|---|---|---|
Strict-Transport-Security |
强制 HTTPS | max-age=31536000; includeSubDomains |
X-Content-Type-Options |
禁止 MIME 嗅探,防类型混淆攻击 | nosniff |
X-Frame-Options |
禁止页面被 iframe 嵌套,防点击劫持 | SAMEORIGIN 或 DENY |
X-XSS-Protection |
旧版 XSS 过滤(现代浏览器已废弃,保留无害) | 1; mode=block |
Referrer-Policy |
控制向第三方泄露哪些来源信息 | strict-origin-when-cross-origin |
Content-Security-Policy |
白名单允许加载的脚本/样式/图片,防 XSS 注入 | 按站点收紧 |
Permissions-Policy |
禁掉用不到的权限(摄像头/麦克风) | camera=(), microphone=() |
一个"安全头套餐"配置示例(放在 server 块,always 保证错误响应也带上):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
注意 |
add_header在location里会覆盖上层server的同名字段。如果你在某个location里也写了add_header,那server级别的全部安全头都会失效。最常见坑:在location /放了proxy_pass又加了自己的add_header,导致根级安全头全丢。解决:要么统一放在一个位置,要么把安全头抽成include片段。
检查结果¶
用 curl 看你的站点实际返回了哪些头:
curl -sSI https://learn.bangdream.xyz/ | grep -iE "strict-transport|x-content-type|x-frame|referrer|content-security"
延伸:Content-Security-Policy 实战¶
CSP 是"白名单",只有白名单内的来源才允许执行。一个站点想用 CDN 引脚本、内联样式,可这样配:
add_header Content-Security-Policy "default-src 'self'; img-src 'self' https:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'" always;
提示 | CSP 配太严会造成白屏,配太松等于没配。先用
Content-Security-Policy-Report-Only跑一段线上观察违规,再切正式策略。
相关命令¶
- 查看证书的 OCSP 响应与证书链:
openssl s_client -connect <域名>:443 -status -showcerts - 一键安全体检:
curl -sSI https://<域名>/人工核对头;或用在线工具(如 Mozilla Observatory)扫描。 - 禁止子域 URL 泄露:
add_header Referrer-Policy "no-referrer"(对隐私敏感站点)。