csp默认阻止内联脚本和样式,因无法区分开发者代码与攻击者注入的恶意代码;应使用动态生成的nonce或静态哈希替代'unsafe-inline',禁用strict-dynamic滥用。

内联脚本和样式为什么被CSP阻止
CSP默认禁止inline-script和inline-style,因为攻击者一旦注入<script>alert(1)</script>或onerror="alert(1)"这类代码,就能直接执行任意JS。浏览器不区分“开发者写的内联”和“攻击者注入的内联”,一概拦截。
常见错误现象包括:Refused to execute inline script because it violates the following Content Security Policy directive,或样式不生效但控制台没报错(其实是style-src没放行'unsafe-inline',而你又没用nonce)。
用nonce代替'unsafe-inline'
'unsafe-inline'是反模式——它等于把CSP的内联防护完全关掉。真正安全的做法是为每个内联资源生成唯一nonce值,并在CSP头和HTML中同步使用。
- 服务端生成随机base64字符串(如
Base64.encode(SecureRandom.bytes(16))),作为本次响应的nonce - HTTP响应头中加入:
Content-Security-Policy: script-src 'nonce-abc123' https: - HTML中对应内联脚本写成:
<script nonce="abc123">console.log('ok');</script> - 注意:每次HTTP响应必须用新
nonce,不能复用;也不能硬编码在模板里
hash方式只适用于静态内联代码
如果内联脚本/样式内容完全固定(比如一段初始化配置JSON),可用sha256哈希值白名单。但只要内容含动态变量(如<script>init({id: <%= user.id %>})</script>),哈希就失效。
- 计算哈希命令示例:
echo -n "console.log('hello');" | shasum -a 256 | awk '{print $1}'→ 得到sha256-abc... - CSP头中添加:
script-src 'sha256-abc123...' https: - 该方式不防篡改,只防注入;且无法用于含服务端插值的内联代码
- 不推荐用于
style标签,因CSS解析对空格/换行敏感,哈希极易不匹配
避免strict-dynamic滥用
strict-dynamic允许由可信脚本动态创建的内联执行(如eval()、innerHTML插入的<script></script>),但它不解决原始内联问题,反而可能扩大攻击面。
- 仅当已用
nonce保护了首屏加载脚本,且后续脚本全由它动态注入时,才考虑加'strict-dynamic' - 不要和
'unsafe-inline'共存——后者会让strict-dynamic失效 - 主流浏览器支持度尚可,但IE完全不支持,若需兼容旧环境,不能依赖它
真正难的是服务端集成:nonce必须随每次响应生成、透传到模板、且不能泄露(比如别打日志)。漏掉任意一环,策略就形同虚设。











