默认情况下,CSP 的 script-src 指令禁止内联脚本执行,包括 <script> 块、事件属性(如 onclick)和 javascript: 伪协议;安全启用需用动态 nonce 配合带 nonce 属性的 <script> 标签,而事件处理器必须重构为 addEventListener 方式。

默认情况下,CSP 的 script-src 指令就禁止内联脚本执行——你什么也不用做,它就已经生效了。真正需要操心的,是怎么在禁用的前提下,安全地保留必要功能。
为什么 script-src 'self' 会拦掉所有内联脚本
浏览器把以下三类都算作“内联脚本”,只要没显式放行,一律拒绝:
-
<script>alert(1)</script>这种直接写在 HTML 里的 script 块 -
<button onclick="doIt()">这类事件属性(onload、onchange等同理) -
javascript:void(0)或href="javascript:..."这类伪协议
报错信息通常是:Refused to execute inline script 或 Refused to execute inline event handler。这不是配置错了,而是 CSP 正常工作。
想保留某段内联脚本?别加 'unsafe-inline',用 nonce
给特定 <script> 标签加一次性令牌,比全局放开更可控:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
立即学习“前端免费学习笔记(深入)”;
- 服务器生成随机 nonce 值(如
b1967a39a02f45edbac95cbb4651bd12),拼进响应头:Content-Security-Policy: script-src 'self' 'nonce-b1967a39a02f45edbac95cbb4651bd12' - 对应 script 标签必须带相同值:
<script nonce="b1967a39a02f45edbac95cbb4651bd12">console.log('safe');</script> - 注意:nonce 必须每次响应都刷新,不能硬编码;且不适用于
onclick等事件属性——它们无法挂 nonce 属性
内联事件处理器(onclick 等)根本没法用 nonce,只能重构
这是最容易被忽略的坑:nonce 只对 <script> 标签有效,对 HTML 属性无效。所以:
-
<button onclick="submitForm()">→ 一定会被拦,无论你怎么配 nonce - 正确做法是剥离逻辑,改用
addEventListener:document.getElementById('btn').addEventListener('click', submitForm) - 如果用 HTMX,设
htmx.config.allowEval = false避免它内部触发 eval;如果用 sockjs-client,优先选 WebSocket 传输而非 JSONP(后者依赖内联回调)
最麻烦的不是配策略,而是清理历史代码里散落的 onclick、onsubmit 和内联 <script> ——它们不会报错直到上线,但一旦 CSP 生效,就是静默失效。


















