一、为什么需要安全响应头
HTTP 响应头中的安全策略是浏览器与服务器之间的"约定",告诉浏览器应该如何处理页面内容、限制哪些行为。缺少这些头会被安全扫描工具标记为漏洞,也会在实际攻击中留下可利用的空间。
二、各安全头含义速查
| 响应头 | 作用 | 可选参数 | 推荐值 |
|---|---|---|---|
X-Content-Type-Options | 禁止浏览器 MIME 类型嗅探,防止 XSS | nosniff(唯一有效值) | nosniff |
X-XSS-Protection | 启用旧版浏览器内置 XSS 过滤器 | 0 禁用 / 1 启用 / 1; mode=block 启用并阻断 / 1; report=<url> 启用并上报 | 1; mode=block |
X-Frame-Options | 控制页面是否允许被 iframe 嵌套,防点击劫持 | DENY 完全禁止 / SAMEORIGIN 仅同域名 / ALLOW-FROM <url> 指定域名(已废弃) | SAMEORIGIN |
Referrer-Policy | 控制跨域请求时 Referrer 信息的携带范围 | no-referrer 不发送 / no-referrer-when-downgrade / origin 仅域名 / origin-when-cross-origin / same-origin 仅同域 / strict-origin / strict-origin-when-cross-origin / unsafe-url 始终完整发送 | strict-origin-when-cross-origin |
X-Permitted-Cross-Domain-Policies | 禁止 Flash/PDF 等加载跨域策略文件 | none 完全禁止 / master-only 仅主策略文件 / by-content-type / by-ftp-filename / all 全部允许 | none |
X-Download-Options | 禁止 IE 直接在浏览器中打开下载文件 | noopen(唯一有效值) | noopen |
Content-Security-Policy | 白名单控制页面可加载的资源来源,最全面的 XSS 防护 | 指令众多,常用:default-src / script-src / style-src / img-src / font-src / frame-src / frame-ancestors / form-action / connect-src / media-src;来源值:'self' / 'none' / 'unsafe-inline' / 'unsafe-eval' / 'nonce-<value>' / <url> | default-src 'self' 按需扩展各指令 |
Permissions-Policy | 控制页面可使用的浏览器硬件/敏感 API 权限 | 格式:feature=(allowlist);常用功能:camera / microphone / geolocation / payment / usb / fullscreen / accelerometer / gyroscope;allowlist:() 禁用 / (self) 仅同域 / (*) 全部允许 / (<origin>) 指定域名 | 按需禁用,fullscreen=(self) |
Cross-Origin-Resource-Policy | 控制资源是否允许被跨域页面通过标签加载 | same-origin 仅同域名 / same-site 含子域名 / cross-origin 允许任意跨域(等同不设置) | same-origin 或 same-site |
Clear-Site-Data | 清除客户端缓存/Cookie/Storage | "cache" / "cookies" / "storage" / "executionContexts" / "*" 全部清除;可组合使用 | 退出登录接口用 "cache", "cookies", "storage" |
三、Nginx 配置
将以下内容放入 server {} 块,或提取为独立 include 文件统一管理:
Yaml1# /etc/nginx/conf.d/security-headers.conf 2 3# 禁止 MIME 类型嗅探 4add_header X-Content-Type-Options "nosniff" always; 5 6# 启用浏览器 XSS 过滤器(兼容旧版浏览器) 7add_header X-XSS-Protection "1; mode=block" always; 8 9# 允许同域名 iframe 嵌套,阻止跨域嵌套 10add_header X-Frame-Options "SAMEORIGIN" always; 11 12# 同域名携带完整 Referrer,跨域仅传域名 13add_header Referrer-Policy "strict-origin-when-cross-origin" always; 14 15# 禁止 Flash/PDF 跨域策略文件加载 16add_header X-Permitted-Cross-Domain-Policies "none" always; 17 18# 禁止 IE 直接打开下载文件 19add_header X-Download-Options "noopen" always; 20 21# 仅允许同站资源加载(防止 Spectre 等旁信道攻击) 22add_header Cross-Origin-Resource-Policy "same-site" always; 23 24# 禁用不必要的浏览器硬件/API 权限 25add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)" always; 26 27# 内容安全策略:仅允许同域名资源 28add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-src 'self'; frame-ancestors 'self'; form-action 'self';" always;
退出登录接口单独配置 Clear-Site-Data:
Plain1# 仅在退出登录接口响应时清除客户端数据 2location = /api/logout { 3 proxy_pass http://your_backend; 4 add_header Clear-Site-Data '"cache", "cookies", "storage"' always; 5}
⚠️ Nginx add_header 继承陷阱
Nginx 中,子级 location 块一旦使用了 add_header,父级 server 块的所有 add_header 配置将全部失效。
解决方案:将所有安全头提取到独立文件,在每个有 add_header 的 location 块中 include 进来:
Yaml1location /some-path { 2 include conf.d/security-headers.conf; 3 add_header Cache-Control "no-store"; 4 # ... 5}
四、Next.js 15 配置
Next.js 支持通过 next.config.mjs 的 headers() 方法配置响应头,无需依赖 Nginx 即可覆盖大部分场景:
JavaScript1// next.config.mjs
2const securityHeaders = [
3 { key: 'X-Content-Type-Options', value: 'nosniff' },
4 { key: 'X-XSS-Protection', value: '1; mode=block' },
5 { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
6 { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
7 { key: 'X-Permitted-Cross-Domain-Policies', value: 'none' },
8 { key: 'X-Download-Options', value: 'noopen' },
9 { key: 'Cross-Origin-Resource-Policy', value: 'same-site' },
10 { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)' },
11 {
12 key: 'Content-Security-Policy',
13 value: [
14 "default-src 'self'",
15 "script-src 'self'",
16 "style-src 'self' 'unsafe-inline'",
17 "img-src 'self' data:",
18 "font-src 'self'",
19 "frame-src 'self'",
20 "frame-ancestors 'self'",
21 "form-action 'self'",
22 ].join('; '),
23 },
24]
25
26const nextConfig = {
27 async headers() {
28 return [
29 {
30 source: '/(.*)', // 匹配所有路由
31 headers: securityHeaders,
32 },
33 ]
34 },
35}
36
37export default nextConfig
Next.js 配置的覆盖范围限制
Next.js 的 headers() 只作用于 Next.js 处理的路由响应,以下情况不会附加安全头:
public/目录下的静态文件(由 Nginx/CDN 直接托管时)- Next.js 进程之外的 Nginx 层响应(如 Nginx 自身返回的 404)
推荐做法:Next.js config 负责应用层路由,Nginx 负责兜底静态资源和错误页,两端同时配置。
五、CSP 按需调整
默认的 CSP 策略较为严格,实际项目中常见的调整场景:
Yaml1# 引入了 CDN 上的 JS 库
2script-src 'self' https://cdnjs.cloudflare.com;
3
4# 使用了 Google Fonts
5font-src 'self' https://fonts.gstatic.com;
6style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
7
8# 需要加载第三方图片
9img-src 'self' data: https://your-cdn.com;
CSP 调整前建议先用 Content-Security-Policy-Report-Only 模式观察拦截情况,再切换为强制模式,避免直接阻断线上业务。