Helmet 响应头完整速查
本章以当前 Helmet 官方行为为依据讲解主要 Header。Helmet 会随版本调整默认值,因此升级依赖时应同时查看官方文档和真实响应,不能只依赖教程中的静态清单。
可以用下面的命令确认当前项目实际返回的 Header:
curl -i http://127.0.0.1:8080/health
1. 默认策略总览
调用 app.use(helmet()) 时,常见默认行为如下:
| Header/行为 | 常见默认状态 | 主要作用 |
|---|---|---|
Content-Security-Policy |
开启 | 限制页面资源和脚本执行 |
Cross-Origin-Opener-Policy |
开启 | 隔离跨源浏览上下文 |
Cross-Origin-Resource-Policy |
开启 | 限制其他源使用响应资源 |
Origin-Agent-Cluster |
开启 | 请求按 Origin 隔离代理集群 |
Referrer-Policy |
开启 | 控制 Referer 信息 |
Strict-Transport-Security |
开启 | 要求后续使用 HTTPS |
X-Content-Type-Options |
开启 | 禁止 MIME 嗅探 |
X-DNS-Prefetch-Control |
开启 | 控制 DNS 预取 |
X-Download-Options |
开启 | 限制旧版 IE 下载文件直接打开 |
X-Frame-Options |
开启 | 限制页面被 iframe 嵌入 |
X-Permitted-Cross-Domain-Policies |
开启 | 限制旧插件跨域策略 |
X-Powered-By |
移除 | 不暴露 Express 标识 |
X-XSS-Protection |
设置为 0 |
关闭有历史问题的旧式 XSS 过滤器 |
Cross-Origin-Embedder-Policy |
通常默认关闭 | 要求嵌入资源满足跨源隔离规则 |
“默认开启”不等于适合所有业务。下面逐项说明具体影响。
2. Content-Security-Policy(CSP)
示例:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self'
CSP 是 Helmet 中影响最广的一项。它通常附在 HTML 文档响应上,由浏览器约束该文档可以加载或执行什么。
高频 directive
| Directive | 控制对象 | 配错后的常见现象 |
|---|---|---|
default-src |
未单独声明类型时的兜底来源 | 多种资源同时失败 |
script-src |
JavaScript 来源及执行方式 | 页面按钮失效、白屏 |
style-src |
CSS 和内联样式 | 页面失去样式 |
img-src |
图片来源 | CDN、data URL 图片失败 |
font-src |
字体来源 | 图标或字体回退 |
connect-src |
fetch、XHR、WebSocket、EventSource | API 请求在浏览器端被 CSP 阻止 |
object-src |
<object>、插件内容 |
嵌入内容失败,通常建议 'none' |
frame-src |
当前页面可以嵌入哪些 frame | 第三方页面无法嵌入 |
frame-ancestors |
谁可以 iframe 嵌入当前页面 | 外部系统嵌入失败 |
base-uri |
<base> 可使用的 URL |
阻止恶意重写相对 URL 基准 |
form-action |
表单可以提交到哪里 | 第三方表单提交失败 |
upgrade-insecure-requests |
把 HTTP 子资源升级为 HTTPS | 本地开发 URL 可能被升级 |
'self' 的含义
'self' 是当前文档的 Origin,不是“本公司所有域名”。页面在 https://www.example.com 时,'self' 不自动包含 https://api.example.com。
例如页面需要连接 API:
Content-Security-Policy: default-src 'self'; connect-src 'self' https://api.example.com
CORS 即使允许了 www.example.com,若页面自己的 CSP connect-src 没有允许 API,fetch 仍会失败。这是 Helmet 与 CORS 看似“冲突”的典型来源。
JSON API 与 HTML 的差别
API 的 JSON 响应带 CSP,通常只约束该响应被当作文档打开时的行为,不会控制发起 fetch 的原页面。要保护 Nginx 返回的前端页面,应在 index.html 的响应上设置匹配前端构建产物的 CSP。
Report-Only
上线前可先观察违规而不直接阻断:
Content-Security-Policy-Report-Only: ...
Report-Only 适合收集真实资源来源并逐步收紧,但它本身不提供阻断保护,不能作为永久替代。
3. Cross-Origin-Opener-Policy(COOP)
常见值:
Cross-Origin-Opener-Policy: same-origin
COOP 控制顶级页面与通过 window.open() 打开的页面是否处于同一浏览上下文组。same-origin 可以降低跨源窗口侧信道风险,但可能让跨源窗口的 window.opener 关系被切断。
高风险兼容场景:
- OAuth 登录弹窗;
- 支付页面弹窗;
- 跨域后台系统通过 opener 回传结果。
普通 JSON fetch 通常不会因为 COOP 失败。问题更多出现在 Express 直接返回 HTML 页面时。
4. Cross-Origin-Embedder-Policy(COEP)
可能的值:
Cross-Origin-Embedder-Policy: require-corp
COEP 要求页面嵌入的跨源资源明确通过 CORS 或 CORP 授权,是启用跨源隔离能力(例如部分 SharedArrayBuffer 场景)的一环。Helmet 通常不会默认启用它,因为它容易让第三方图片、脚本、字体和 iframe 突然失效。
只有在确实需要跨源隔离,并能控制所有资源响应头时再启用。COEP 是页面策略;纯 JSON API 是否受影响取决于它是否被该页面作为资源加载。
5. Cross-Origin-Resource-Policy(CORP)
常见默认值:
Cross-Origin-Resource-Policy: same-origin
CORP 是响应资源对使用方的声明:哪些源可以把它作为资源加载。
| 值 | 含义 |
|---|---|
same-origin |
只允许同源使用 |
same-site |
允许同站点使用 |
cross-origin |
允许跨源使用 |
它和 CORS 不等价:CORS 主要控制跨源 JavaScript 读取响应;CORP 主要防止响应被不被允许的页面嵌入或加载。在跨域图片、文件预览、CDN 和启用 COEP 的页面中尤其要关注。
如果 API 只由同源路径 /api 调用,默认通常影响不大;若 api.example.com 返回图片给 www.example.com 显示,则应进行真实浏览器测试,并按资源用途选择 CORP/CORS,而不是直接全局放宽。
6. Origin-Agent-Cluster
常见值:
Origin-Agent-Cluster: ?1
它请求浏览器按 Origin 而不是更宽泛的 Site 来隔离代理集群,减少不同 Origin 共享某些执行环境的机会。普通业务通常感知不到,也很少需要单独修改。
它不是服务器 Cluster,也不是 Node.js cluster 模块;这里的 Agent Cluster 是浏览器内部概念。
7. Referrer-Policy
常见默认值:
Referrer-Policy: no-referrer
它控制浏览器访问下一资源时发送多少来源 URL 信息。策略越严格,隐私越好,但依赖 Referer 的统计、反盗链或业务跳转可能缺少数据。
常见策略:
no-referrer:完全不发送;same-origin:只在同源请求发送;strict-origin-when-cross-origin:同源发送完整 URL,安全的跨源请求只发送 Origin,是现代浏览器常见默认思路。
注意规范中的请求头拼写历史上是 Referer,而策略响应头是 Referrer-Policy。
8. Strict-Transport-Security(HSTS)
常见形式:
Strict-Transport-Security: max-age=31536000; includeSubDomains
浏览器通过 HTTPS 收到该 Header 后,会在 max-age 时间内自动把该主机的 HTTP 访问升级为 HTTPS。它能降低降级攻击和用户误用 HTTP 的风险。
上线风险:
includeSubDomains会影响所有子域名,某个仍只支持 HTTP 的旧系统可能无法访问;- 长时间
max-age不容易立刻撤销; - 在 HTTPS 由 Nginx 终止时,通常由最外层 Nginx 统一设置更清晰;
- 浏览器忽略通过纯 HTTP 收到的 HSTS,但本地共用域名或错误代理配置仍可能干扰测试。
不要在 HTTPS、证书和所有相关子域名尚未准备好时盲目启用长期 HSTS,更不要轻率加入预加载列表。
9. X-Content-Type-Options
固定形式:
X-Content-Type-Options: nosniff
浏览器不应把声明为一种 MIME 的内容猜成另一种可执行类型。它提升安全性的同时会暴露服务器配置错误:
- JavaScript 却返回
text/html,脚本可能被拒绝; - CSS 返回错误 Content-Type,样式可能不加载;
- API JSON 应正确返回
application/json。
遇到问题应修正 Content-Type,而不是优先关闭 nosniff。
10. X-Frame-Options
常见默认值:
X-Frame-Options: SAMEORIGIN
DENY:任何页面都不能嵌入;SAMEORIGIN:只允许同源页面嵌入。
它用于降低点击劫持风险。更现代、更灵活的替代是 CSP frame-ancestors,可以声明多个允许来源。为了兼容旧浏览器,项目可能同时设置两者,但策略应保持一致。
API JSON 通常不会被正常 iframe 使用,因此影响有限;Express 若提供 Swagger、报表或 HTML 预览,则要确认是否有合法嵌入需求。
11. X-DNS-Prefetch-Control
常见形式:
X-DNS-Prefetch-Control: off
它控制浏览器是否预先解析页面中链接的域名。关闭可减少一些隐私泄漏和非必要网络行为,但也可能失去少量性能优化。它主要影响 HTML 页面,不是 API fetch 的核心安全项。
12. X-Download-Options
常见形式:
X-Download-Options: noopen
它主要针对旧版 Internet Explorer,降低用户直接在网站上下文中打开下载文件的风险。现代浏览器中的影响很有限,不能代替安全的 Content-Disposition、文件类型验证和病毒扫描。
13. X-Permitted-Cross-Domain-Policies
常见形式:
X-Permitted-Cross-Domain-Policies: none
它限制 Adobe Flash、Acrobat 等旧式客户端读取跨域策略文件。现代 Web 应用中存在感较低,但作为防御性默认项成本也较低。
14. X-Powered-By
Express 默认可能返回:
X-Powered-By: Express
Helmet 会移除它,减少不必要的技术栈暴露。但隐藏名称不能阻止攻击者识别技术栈,更不能替代升级依赖和修复漏洞。
也可以直接使用:
app.disable("x-powered-by");
15. X-XSS-Protection
Helmet 会将其设置为:
X-XSS-Protection: 0
这是有意关闭旧浏览器内置、曾产生安全副作用的 XSS Auditor,而不是“关闭应用的 XSS 防护”。现代防线应依靠正确转义、CSP 和安全编码。
16. 不要重复设置相互矛盾的值
当 Nginx 和 Express 都添加安全头时,可能出现重复 Header 或外层覆盖内层的情况。浏览器对不同 Header 的重复值处理并不完全一致,不应依靠猜测。
建议:
- HTML 页面策略由实际提供 HTML 的服务负责;
- HSTS 通常由最外层 HTTPS 入口负责;
- API 专属策略由 Express 负责;
- 在最终公网响应上用 curl 和浏览器确认,而不只检查 Express 本机端口。