CSP识别的hash值需对内联脚本内容(不含标签)做UTF-8编码后计算SHA-256,再base64编码;例如alert(1)生成sha256-qznLcsROx4GAYnkPvH3tkvhUL6Vf9o1IvEOw1mTHlJk=,填入script-src 'sha256-...'即可生效。 h
长期稳定更新的攒劲资源: >>>点此立即查看<<<
正确的姿势是什么?其实很简单,只取脚本标签内部的内容。也就是说,把首尾的和标签去掉,只对alert(1)这部分纯文本下手。接着,将这段文本进行UTF-8编码,计算其SHA-256哈希值,最后再进行base64编码(注意,base64字符串里不能有换行或空格)。
在命令行里,这个过程通常是这样操作的:
echo -n "alert(1)" | shasum -a 256 | xxd -r -p | base64
最终,你会得到一个类似qznLcsROx4GAYnkPvH3tkvhUL6Vf9o1IvEOw1mTHlJk=的字符串。把它放进策略里,完整的格式就是:script-src 'sha256-qznLcsROx4GAYnkPvH3tkvhUL6Vf9o1IvEOw1mTHlJk='。这样,对应的内联脚本才能顺利执行。
这问题问到了点子上。如果你的内联脚本里包含了服务端变量,比如alert(<%= user.name %>),那么哈希值必须基于最终渲染完成后的、确切的Ja vaScript字符串来计算。这意味着,不同用户、不同会话下生成的脚本内容可能不同,对应的哈希值也就无法复用,必须动态生成。
不过,这里有几个容易踩的“雷区”,需要特别注意:
${name}这样的前端模板语法,它并不会在服务端被解析成最终值,而是原封不动地送到浏览器。CSP校验的正是HTML里的原始文本,而非浏览器执行后的结果,所以哈希必然会失效。document.write或eval动态生成的脚本,CSP的哈希白名单机制是管不了的。因为CSP在校验时,根本不会去检查这些运行时注入的内容。说到底,只要脚本内容在HTML送达浏览器之前就已经是确定的、静态的,就可以用哈希。否则,就得考虑其他方案了。
当一个页面有多个内联脚本块时,管理起来就需要点技巧了。原则是:一个脚本,一个哈希。在CSP策略里,用空格把这些哈希值分隔开就行,例如:
Content-Security-Policy: script-src 'sha256-A1B2...' 'sha256-C3D4...' 'self'
但别高兴太早,这里藏着几个限制:
nonce方案了。Refused to execute inline script错误,不会告诉你具体是哪条脚本出的问题。'unsafe-inline'来绕过限制。但务必记住,这个指令一旦存在,会使所有哈希规则失效。所以在上线前,必须把它移除。明明哈希值算对了,策略也配了,脚本还是被拦?这种时候,问题往往出在一些HTML解析的细微之处。
和 是两码事。后者的脚本内容实际上包含了type="text/ja vascript"这个字符串,计算哈希时自然得到不同的结果。\r\n)与Linux工具默认的换行符(\n)不匹配,都会导致哈希值“失之毫厘,谬以千里”。标签来声明CSP,并且这个标签放在了标签之后,部分浏览器可能会忽略它,导致策略未能生效。所以,真要依靠哈希白名单这套机制,就必须把内联脚本当作“编译产物”来严格管理:内容锁定、生成自动化、上线前必须验证。这套流程但凡有一点松动,等待你的就只剩下浏览器的报错和一片空白的控制台了。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述