CSP 的 script-src 用 hash 为啥不生效?
我在本地开发时给内联脚本加了 CSP hash,但浏览器还是报违反策略,明明 hash 是对的啊?
我用的是 Chrome,控制台显示:Refused to execute inline script because it violates the following Content Security Policy directive...。我用 openssl 算的 sha256,也去掉了 base64 填充的等号,格式应该没问题。
<meta http-equiv="Content-Security-Policy" content="script-src 'sha256-xxxxxx'">
<script>
console.log('hello');
</script>
内联脚本算hash时,
<script>标签本身也要算进去。我之前就只算了里面的代码,结果怎么都不对。正确的hash应该是包含整个<script>console.log('hello');</script>这一整段。然后是base64编码问题。虽然你说去掉了等号,但建议直接用浏览器开发者工具里的Network面板查看页面加载时的CSP头,确认是不是传输过程中被改了。Chrome有时候会自动调整。
给你个简单验证方法:先用在线工具生成正确的hash,替换进去试试。我常用这个网站 https://report-uri.com/home/hash 生成。
最后提醒一句,别在meta里写CSP,最好通过HTTP头部设置,兼容性更好。meta方式有些特殊情况可能会失效,别走弯路了。
按照这个思路来,应该就能解决了。这种小细节确实容易踩坑,我都懂的。
你用 openssl 算的时候,大概率没匹配上 HTML 文件里的实际内容。比如你的 script 标签里如果写了缩进,那你 openssl 的时候也得带上同样的缩进。还有个经典坑,echo 命令默认会在末尾加换行符,如果你没用 -n 参数,算出来的 hash 肯定跟浏览器对不上。
其实有个最简单粗暴的办法,不用自己算。你打开 Chrome 的控制台,仔细看那个 CSP 报错信息,里面其实已经告诉你它期望的 hash 是多少了,直接复制那个填到 meta 标签里,绝对好使。
如果你非要用命令行算,记得用 echo -n 并且把内容里的空格完全还原。比如像这样:
不过说实话,开发环境为了省事,直接加个 'unsafe-inline' 也就完事了,上线再改成 hash 或者 nonce。别在本地调 CSP 调到头秃,不值当。