csp识别的hash值需对内联脚本内容(不含标签)做utf-8编码后计算sha-256,再base64编码;例如alert(1)生成sha256-qznlcsrox4gaynkpvh3tkvhul6vf9o1iveow1mthljk=,填入script-src 'sha256-...'即可生效。

hash值怎么生成才能被CSP识别
CSP的script-src支持'sha256-xxx'这类哈希白名单,但必须基于脚本内容(不含标签)做SHA-256计算,且编码为base64(无换行、无空格)。常见错误是直接对<script>alert(1)</script>整个字符串哈希——这会导致不匹配。
正确做法:只取alert(1)这部分内容(去除首尾<script></script>和),UTF-8编码后计算SHA-256,再base64编码。例如:
echo -n "alert(1)" | shasum -a 256 | xxd -r -p | base64
输出类似sha256-qznLcsROx4GAYnkPvH3tkvhUL6Vf9o1IvEOw1mTHlJk=,这个值才能放进script-src 'sha256-qznLcsROx4GAYnkPvH3tkvhUL6Vf9o1IvEOw1mTHlJk='生效。
内联脚本里有变量或模板语法怎么办
只要脚本内容在HTML渲染前就完全确定(即服务端静态生成、非客户端JS拼接),就可以生成哈希。但如果含服务端变量(如alert()),哈希必须按最终渲染出的实际JS字符串计算——不同用户、不同上下文产生的哈希可能不同,不能复用。
容易踩的坑:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 前端模板(如
${name})未被服务端解析,而是留到浏览器执行,此时哈希失效——CSP校验的是原始HTML里的文本,不是运行时结果 - 自动格式化工具(Prettier、IDE保存时)给内联脚本加了空格或换行,导致哈希不匹配
- 使用
document.write或eval动态注入的脚本,无法用hash白名单,CSP根本不检查那段内容
多个内联脚本如何管理hash白名单
每个<script></script>块需独立计算哈希,CSP策略中用空格分隔多个hash值。例如:
Content-Security-Policy: script-src 'sha256-A1B2...' 'sha256-C3D4...' 'self'
但要注意:
- 浏览器对单条CSP头长度有限制(通常约1000字符),太多hash会截断,建议合并逻辑或改用nonce
- 构建流程中若脚本内容变更,必须重新生成对应hash,否则页面JS全部被阻断,且控制台只报
Refused to execute inline script,不提示具体哪条没匹配 - 开发环境可临时加
'unsafe-inline'调试,但上线前必须移除——它会使所有hash规则失效
为什么有时候hash写了还是被拦截
最常忽略的是HTML解析细节:
-
<script>console.log(1)</script>和<script type="text/javascript">console.log(1)</script>算作不同内容,后者多出type="text/javascript"字符串,哈希必然不同 - 脚本前后有不可见Unicode字符(如零宽空格、BOM)、Windows换行符(
\r\n)而Linux工具默认用\n,也会导致哈希错位 - HTTP响应头中的CSP未覆盖全部资源(比如通过
<meta http-equiv="Content-Security-Policy">声明,但该标签位置在<script></script>之后,部分浏览器会忽略)
真要靠hash白名单,就得把内联脚本当作“编译产物”来对待:内容锁定、生成自动化、上线前验证。稍有松动,就只剩报错和空白控制台。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










