Security Headers
HTTP 安全响应头是现代 Web 应用中一道基础且经常被忽视的防御层, 它们作为指令指示浏览器启用 原生保护机制,以抵御各种常见的攻击向量。这些 HTTP 响应头充当一种声明式的安全策略,为浏览器应如何 处理和渲染页面内容、控制脚本执行、 管理 cookies 以及与第三方资源交互制定规则。在正确配置的情况下, 诸如 Content-Security-Policy (CSP)、Strict-Transport-Security (HSTS)、X-Frame-Options 和 X-Content-Type-Options 等响应头能够针对 Cross-Site Scripting (XSS)、 clickjacking、MIME sniffing、协议降级以及恶意代码注入等攻击构筑显著的屏障。正确 实现这些响应头是对 Web 应用进行 hardening 最高效的方式之一, 因为它无需修改应用代码,并能对整类漏洞提供即时保护。 研究表明,绝大多数网站仍未妥善实现 这些响应头,使其用户暴露于本可通过相对 简单的 Web 服务器配置加以缓解的攻击之下。考虑到 自动化安全扫描工具将这些响应头的存在与妥善配置 作为衡量应用安全态势的主要指标,这种疏忽尤为严重。
Content-Security-Policy (CSP)
CSP 通过为 scripts、styles、images 及其他资源定义可信来源的 whitelist 来防范 XSS。
# 严格的 CSP(推荐)
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-';
style-src 'self' 'nonce-';
img-src 'self' https: data:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
# 使用 report-only 的 CSP(测试模式)
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri /csp-violation-report
关键的 CSP Directives
- default-src:其他 directives 的 fallback
- script-src:JavaScript 执行的 whitelist
- style-src:允许的 CSS 来源
- frame-ancestors:防范 clickjacking
- upgrade-insecure-requests:强制 HTTPS
Strict-Transport-Security (HSTS)
HSTS 强制浏览器始终使用 HTTPS,防范 downgrade attacks 和 SSL stripping。
# 带 preload 和子域名的 HSTS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# HSTS preload 的步骤:
1. 配置带 preload 的 HSTS 响应头
2. 在 hstspreload.org 提交域名
3. 该域名将被纳入浏览器的 preload lists
X-Frame-Options
通过控制页面是否可在 frame/iframe 中渲染来防范 clickjacking。
# 拒绝所有 framing(最安全)
X-Frame-Options: DENY
# 仅允许同源
X-Frame-Options: SAMEORIGIN
# 允许特定域名(已废弃 - 请使用 CSP frame-ancestors)
X-Frame-Options: ALLOW-FROM https://trusted.com
X-Content-Type-Options
通过强制浏览器遵守所声明的 Content-Type 来防范 MIME sniffing 攻击。
# 禁用 MIME sniffing
X-Content-Type-Options: nosniff
Referrer-Policy
控制在 requests 中发送多少 referrer information。
# 推荐策略
Referrer-Policy: strict-origin-when-cross-origin
# 选项:
# - no-referrer:从不发送 referrer
# - no-referrer-when-downgrade:在 HTTPS→HTTP 时不发送 referrer
# - same-origin:仅发送给同源
# - strict-origin:仅发送 origin(不含 path)
Permissions-Policy
控制页面可使用哪些 browser features 和 APIs(取代 Feature-Policy)。
# 禁用危险的功能
Permissions-Policy:
geolocation=(),
microphone=(),
camera=(),
payment=(),
usb=(),
interest-cohort=()
各服务器的配置
Nginx
# nginx.conf
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self';" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
Apache
# .htaccess 或 httpd.conf
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self';"
Node.js/Express
// 使用 Helmet middleware
const helmet = require('helmet');
app.use(helmet());
// 自定义配置
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-'"],
styleSrc: ["'self'", "'nonce-'"],
}
}));
测试 Security Headers
- securityheaders.com:扫描与 A+ 评级
- Mozilla Observatory:全面分析
- Chrome DevTools:Network 选项卡 → Headers
- curl:
curl -I https://example.com
常见陷阱
- CSP 过于宽松,使用了 'unsafe-inline' 和 'unsafe-eval'
- HSTS 未带 includeSubDomains 使子域名仍可被攻击
- 响应头已配置但未生效(缺少 always 标志)
- 仅测试首页 - 响应头应存在于所有页面
完整检查清单
- [OK] 已配置严格的 Content-Security-Policy
- [OK] HSTS 设置 max-age 为 1 年 + includeSubDomains
- [OK] X-Frame-Options:DENY 或 CSP frame-ancestors
- [OK] X-Content-Type-Options:nosniff
- [OK] 已配置 Referrer-Policy
- [OK] Permissions-Policy 禁用未使用的功能
- [OK] 响应头已在 securityheaders.com 测试(A+ 评级)
- [OK] CSP 已先用 report-only mode 测试
