CSP核心概念
Content Security Policy(CSP)
内容安全策略是W3C制定的Web安全标准,通过HTTP响应头或HTML meta标签定义浏览器允许加载的资源来源白名单。CSP是防御XSS(跨站脚本攻击)的最有效手段之一,被所有现代浏览器支持。策略的名称源自其“内容安全”的定位——它不保护服务器,而是保护客户端浏览器中的页面内容不被恶意篡改。
CSP Level 2 与 Level 3
CSP Level 2于2016年正式发布,引入了base-uri、child-src、form-action、frame-ancestors等指令,以及nonce和hash机制。CSP Level 3仍在持续推进中,新增了strict-dynamic、unsafe-hashes、report-to、worker-src等更细粒度的指令。目前Level 2已被所有主流浏览器广泛支持,Level 3的特性在逐步落地中。
安全关键字
'self'
仅允许加载与当前页面同源的资源,即相同协议(http/https)、相同域名、相同端口。这是最常用的安全关键字,适用于大多数不需要外部资源的场景。例如页面通过https://example.com提供,设置img-src 'self'后只能加载example.com域名下的图片。
'none'
不允许加载任何来源的资源,相当于完全禁止该类型的资源加载。注意'none'必须加引号,且前后需有空格与其他值分隔。通常用于明确禁止某类资源,如object-src 'none'可阻止所有Plugin加载。
'unsafe-inline'
允许页面中的内联脚本(如onclick事件处理器、script标签中的代码)和内联样式。这是一个安全隐患关键字,因为它会大幅削弱CSP对XSS的防护能力。除非绝对必要,应避免使用。如需内联脚本,建议使用nonce或hash替代。
'unsafe-eval'
允许使用eval()、Function()构造器、setTimeout(string)等动态代码执行方法。同样是一个安全隐患关键字,会使CSP无法阻止通过字符串注入的恶意代码。在现代前端框架中,仅在特定场景(如某些模板引擎)下才可能需要。
'strict-dynamic'
信任由已授权脚本(通过nonce或hash授权)动态创建的子脚本。这意味着无需为第三方脚本逐一添加白名单,大大简化了策略配置。配合nonce使用是目前推荐的内联脚本解决方案。需要注意的是,使用strict-dynamic后,'self'和外部域名白名单会被忽略。
Nonce与Hash
Nonce(一次性随机数)
全称Number used once,是CSP Level 2引入的动态授权机制。服务器为每次HTTP响应生成一个唯一的随机字符串,放在CSP头的nonce-xxx值和HTML脚本标签的nonce属性中。浏览器匹配两者后允许该内联脚本执行。关键要求:nonce值必须是加密安全的随机数,且每次请求都应重新生成。
Hash(哈希值)
对脚本或样式内容计算SHA-256/SHA-384/SHA-512哈希值,放入CSP头的sha256-xxx中。浏览器对页面内联脚本计算哈希,匹配后允许执行。优点是无需服务端动态生成,适合静态内容。缺点是脚本内容任何微小变化(包括空格、换行)都需要更新哈希值。
部署相关
Content-Security-Policy-Report-Only
CSP的仅报告模式。与正式的Content-Security-Policy头不同,Report-Only模式下浏览器只会记录违规行为(通过console或report-uri上报),而不会实际阻止资源加载。这是部署CSP前的必备测试步骤,可以在不影响用户体验的前提下收集违规数据。
Report-URI / Report-To
CSP违规报告的接收端点。当浏览器检测到违反CSP策略的资源加载时,会向该端点发送JSON格式的违规报告。report-uri是Level 2的标准,report-to是Level 3的替代方案,使用更灵活的Reporting API。通过分析违规报告,可以持续优化CSP策略。
Frame-Ancestors
控制当前页面可以被哪些来源的iframe嵌入,用于防御点击劫持攻击。它替代了旧的X-Frame-Options响应头,提供了更灵活的配置能力。设置为'self'时仅允许同源页面嵌入,设置为'none'时完全禁止嵌入。
UD5工具箱