Content-Security-Policy

Content-Security-Policy(CSP,内容安全策略)是一个强大的HTTP响应头,通过白名单机制精确控制浏览器可加载和执行的资源(如脚本、样式、图片等),从根本上防御跨站脚本(XSS)、点击劫持、数据注入等代码执行类攻击。其核心思想是“仅允许加载明确授权的资源”,替代了传统依赖“检测恶意内容”的被动防御模式。

一、CSP的核心机制:白名单控制

CSP通过一系列指令(Directives) 定义“允许加载的资源类型”和“资源来源”,浏览器严格按照指令执行,拒绝任何未授权的资源加载或代码执行。

1. 核心指令:控制资源加载范围

CSP的指令按“资源类型”分类,每个指令指定该类型资源的合法来源(白名单)。以下是常用核心指令:

指令 作用(控制哪种资源) 示例值(合法来源)
default-src 所有资源的默认来源(未单独指定的资源继承此规则) 'self' https://cdn.example.com(仅允许自身域名和指定CDN)
script-src JavaScript脚本(最关键,防御XSS的核心) 'self' 'unsafe-inline'(允许自身域名脚本和内联脚本,不推荐'unsafe-inline')
style-src CSS样式表 'self' https://fonts.googleapis.com(允许自身和Google字体的样式)
img-src 图片资源(<img>、背景图等) 'self' data: https://*.example.com(允许自身、data URI和example子域的图片)
connect-src 网络请求(XMLHttpRequest、Fetch、WebSocket等) 'self' https://api.example.com(仅允许自身和指定API域名的请求)
font-src 字体资源 'self' https://fonts.gstatic.com(允许自身和Google字体的字体文件)
object-src 插件资源(<object>、<embed>、<applet> 'none'(禁止所有插件,现代网站几乎不用)
frame-src 嵌套框架(<iframe>、<frame> 'self' https://trusted.com(仅允许自身和可信域名的框架)
media-src 音视频资源(<audio>、<video> 'self' https://stream.example.com(允许自身和指定流媒体域名)
manifest-src Web应用清单(manifest文件) 'self'
worker-src Web Worker 或 Service Worker 脚本的来源 'self' https://stream.example.com (允许自身和指定域名)

2. 指令值:定义“合法来源”的格式

每个指令的取值(合法来源)支持多种格式,覆盖不同场景:

类型 示例 说明
关键字 'self' 允许与当前页面同源(协议+域名+端口完全一致)的资源
'none' 禁止所有来源(优先级高于其他值)
'unsafe-inline' 允许内联脚本/样式(如<script>代码</script>onclick事件),有安全风险(可能被XSS利用)
'unsafe-eval' 允许动态代码执行(如eval()new Function()),有安全风险
'strict-dynamic' 允许由已信任脚本动态生成的脚本(配合nonce/哈希使用,增强灵活性)
域名/URL https://example.com 允许指定域名的资源(精确匹配)
https://*.example.com 允许example.com的所有子域名(通配符*匹配任意子域)
*.example.com 允许example.com的所有子域(包括二级、三级子域),但不包括example.com本身
协议 data: 允许data URI(如data:image/png;base64,...
https: 允许所有HTTPS协议的资源(不限制域名)
哈希值 'sha256-abc123...' 允许内容哈希匹配的内联脚本/样式(替代'unsafe-inline',更安全)
随机数(nonce) 'nonce-随机字符串' 允许带指定nonce属性的内联脚本/样式(每次请求生成随机值,防御重放攻击)

示例:一个严格的CSP策略

Content-Security-Policy: 
  default-src 'self';  # 默认仅允许同源资源
  script-src 'self' https://trusted-cdn.com 'nonce-67890' 'sha256-abc123...';  # 脚本仅允许同源、可信CDN、指定nonce和哈希的内联脚本
  style-src 'self' 'unsafe-inline';  # 样式允许同源和内联(暂时无法避免内联时使用)
  img-src 'self' data: https://*.example.com;  # 图片允许同源、data URI和example子域
  connect-src 'self' https://api.example.com;  # API请求仅允许同源和指定API域名
  object-src 'none';  # 禁止所有插件
  frame-src 'self';  # 仅允许同源框架
  upgrade-insecure-requests;  # 自动将HTTP请求升级为HTTPS
  report-uri /csp-report-endpoint;  # 违规报告发送到指定端点

二、特殊机制:增强安全性的关键指令

除了基础资源控制,CSP还包含多个特殊指令,用于解决特定安全问题:

1. 防御内联脚本/样式:nonce与哈希

内联脚本(如<script>alert(1)</script>)和内联事件(如onclick="...")是XSS攻击的主要载体。CSP默认禁止内联代码(除非用'unsafe-inline',但风险高),推荐用nonce哈希实现安全的内联代码允许:

  • nonce机制
    服务器每次响应生成随机字符串(nonce),在CSP中声明并在 inline 脚本标签中添加nonce属性,仅匹配的内联脚本允许执行。
    示例:

    # 响应头
    Content-Security-Policy: script-src 'nonce-8f4d8a2b7c3e' 'self'
    
    <!-- 页面中的内联脚本(仅带正确nonce的允许执行) -->
    <script nonce="8f4d8a2b7c3e">
      console.log("安全的内联脚本");
    </script>
    
  • 哈希机制
    计算内联脚本/样式的哈希值(SHA-256、SHA-384、SHA-512),在CSP中声明,仅哈希匹配的内联代码允许执行。
    示例:

    # 响应头(内联脚本"console.log('safe')"的SHA-256哈希)
    Content-Security-Policy: script-src 'sha256-abc123...' 'self'
    
    <!-- 哈希匹配,允许执行 -->
    <script>console.log('safe')</script>
    

2. 沙箱模式(sandbox

sandbox指令为页面启用沙箱限制,模拟<iframe sandbox>的效果,限制页面的权限(如禁止表单提交、脚本执行、弹出窗口等)。常用于防御不可信内容(如用户生成的HTML、第三方嵌入内容)。

示例:

# 限制页面不可执行脚本、不可提交表单、不可导航到其他页面
Content-Security-Policy: sandbox allow-same-origin;
  • allow-same-origin:允许页面保留同源权限(否则视为独立源,无法访问同源Cookie);
  • 其他可选值:allow-scripts(允许脚本执行)、allow-forms(允许表单提交)等,默认全部禁止。

3. 升级不安全请求(upgrade-insecure-requests

自动将页面中的HTTP请求升级为HTTPS,解决“混合内容”问题(HTTPS页面加载HTTP资源导致的安全警告或拦截)。

示例:

Content-Security-Policy: upgrade-insecure-requests;
  • 效果:页面中<img src="http://example.com/img.png">会自动变为https://example.com/img.png
  • 配合block-all-mixed-content(禁止所有混合内容)使用,进一步增强安全性。

4. 报告机制(report-uri/report-to

CSP支持将“违反策略的行为”(如加载未授权脚本、执行内联代码)发送到指定服务器端点,用于监控和调试。

  • report-uri(传统方式):

    Content-Security-Policy: default-src 'self'; report-uri /csp-reports;
    

    浏览器会向/csp-reports发送JSON格式的报告,包含违规资源URL、触发指令、页面URL等信息。

  • report-to(现代方式,配合Reporting API):

    Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
    Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-reports"}]}
    

    更强大的报告机制,支持批量发送、过期时间设置等。

5. 强制HTTPS(block-all-mixed-content

禁止HTTPS页面加载任何HTTP资源(混合内容),防止中间人攻击篡改HTTP资源注入恶意代码。

示例:

Content-Security-Policy: block-all-mixed-content;

三、CSP的工作模式

CSP支持两种工作模式,用于不同阶段的部署和调试:

  1. 强制模式(Enforcement)
    浏览器严格执行CSP策略,拒绝未授权资源,并可能阻止页面加载(如script-src违规时可能阻止所有脚本)。
    配置方式:Content-Security-Policy: ...

  2. 仅报告模式(Report-Only)
    浏览器不执行策略(允许未授权资源加载),但会将违规行为发送到report-uri,用于上线前测试策略是否合理(避免误拦截正常资源)。
    配置方式:Content-Security-Policy-Report-Only: ...

四、优势与局限性

优势:

  1. 主动防御XSS:通过白名单限制脚本来源,从根本上阻止未授权脚本执行(即使攻击者注入恶意代码,也会被拦截);
  2. 细粒度控制:可精确到“哪种资源允许从哪个域名加载”,满足复杂业务场景;
  3. 可监控性:通过报告机制实时发现潜在攻击或策略配置问题;
  4. 兼容性好:所有现代浏览器(Chrome、Firefox、Edge、Safari)均支持核心指令。

局限性:

  1. 配置复杂:需梳理所有资源来源(如CDN、第三方服务),初期配置成本高;
  2. 内联代码兼容问题:默认禁止内联脚本/样式,需通过nonce/哈希改造,对老旧系统不友好;
  3. 过度宽松风险:若配置script-src *'unsafe-inline',则CSP几乎失效;
  4. 无法防御所有攻击:对服务器端注入(如SQL注入)、纯数据泄露(如敏感信息直接输出)无防护作用。

五、最佳实践

  1. 从严格到宽松:初期使用default-src 'none',逐步开放必要的资源来源(最小权限原则);
  2. 避免危险值:尽量不用'unsafe-inline''unsafe-eval'*,必须使用时配合nonce/哈希降低风险;
  3. 先测试后上线:先用Report-Only模式运行1-2周,收集违规报告并调整策略,再切换到强制模式;
  4. 结合其他措施:CSP不是银弹,需配合输入验证(过滤恶意输入)、输出编码(转义特殊字符)、HttpOnly Cookie等机制,形成多层防护;
  5. 监控报告:定期分析CSP报告,发现异常访问(如频繁尝试加载恶意域名),及时优化策略。

总结

CSP是现代Web安全的核心机制,通过“白名单控制资源加载”从根本上防御XSS等代码执行攻击。其核心价值在于将安全策略从“被动检测恶意内容”转变为“主动允许可信内容”,大幅降低攻击面。尽管配置复杂,但对于用户数据敏感、安全要求高的应用(如金融、电商、社交),CSP是不可或缺的安全防线。

posted @ 2025-10-11 10:41  小张同学哈  阅读(51)  评论(0)    收藏  举报