Content Security Policy (CSP) 配置实战指南

David Ng | 2026-09-02T01:08:38 | Frontend, Security

详解 Content Security Policy 的各项指令和配置方法,帮助前端应用防御 XSS、数据注入等攻击,并提供逐步收紧策略的迁移路线。

# Content Security Policy (CSP) 配置实战指南 ## 什么是 CSP Content Security Policy 是一种浏览器安全机制,通过 HTTP 头部告诉浏览器哪些资源可以加载和执行。即使攻击者成功注入了恶意脚本,CSP 也能阻止其执行。 ## 快速开始 ``` Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com ``` ## 核心指令详解 ### default-src 所有资源类型的默认策略: ``` # 只允许同源资源 default-src 'self'; # 允许同源和特定 CDN default-src 'self' https://cdn.example.com; ``` ### script-src 控制 JavaScript 的加载和执行: ``` # 同源 + 特定 CDN script-src 'self' https://cdn.example.com; # 使用 nonce(推荐) script-src 'nonce-abc123'; # 使用 hash script-src 'sha256-base64encodedHash='; ``` 在 HTML 中使用 nonce: ```html // 这个脚本会执行 console.log("allowed"); // 这个脚本会被阻止 console.log("blocked"); ``` ### style-src 控制样式表: ``` # 允许内联样式(不推荐但常用) style-src 'self' 'unsafe-inline'; # 使用 nonce(更安全) style-src 'nonce-xyz789'; ``` ### connect-src 控制 XHR、Fetch、WebSocket 请求: ``` connect-src 'self' https://api.example.com wss://ws.example.com https://analytics.example.com; ``` ### img-src / media-src / font-src ``` img-src 'self' data: https: blob:; media-src 'self' https://media.example.com; font-src 'self' https://fonts.gstatic.com; ``` ### frame-ancestors 替代 X-Frame-Options,控制谁可以嵌入你的页面: ``` # 禁止被嵌入(防止 Clickjacking) frame-ancestors 'none'; # 只允许同源嵌入 frame-ancestors 'self'; # 允许特定域名 frame-ancestors 'self' https://partner.example.com; ``` ## Spring Boot 配置 ```java @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.headers(headers -> headers .contentSecurityPolicy(csp -> csp .policyDirectives( "default-src 'self'; " + "script-src 'self' 'nonce-{random}'; " + "style-src 'self' 'unsafe-inline'; " + "img-src 'self' data: https:; " + "connect-src 'self' https://api.example.com; " + "frame-ancestors 'none'" ) ) ); return http.build(); } } ``` 动态 nonce 生成: ```java @Component public class CspNonceFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String nonce = generateNonce(); request.setAttribute("cspNonce", nonce); String policy = String.format( "default-src 'self'; script-src 'self' 'nonce-%s'; " + "style-src 'self' 'nonce-%s'", nonce, nonce); response.setHeader("Content-Security-Policy", policy); chain.doFilter(request, response); } private String generateNonce() { byte[] bytes = new byte[16]; new SecureRandom().nextBytes(bytes); return Base64.getEncoder().encodeToString(bytes); } } ``` ## Nginx 配置 ```nginx server { add_header Content-Security-Policy "default-src 'self'; " "script-src 'self' https://cdn.example.com; " "style-src 'self' 'unsafe-inline'; " "img-src 'self' data: https:; " "font-src 'self' https://fonts.gstatic.com; " "connect-src 'self' https://api.example.com; " "frame-ancestors 'none'" always; } ``` ## 渐进式迁移策略 ### 第一步:Report-Only 模式 先观察,不阻止: ``` Content-Security-Policy-Report-Only: default-src 'self'; report-uri /api/csp-report ``` 收集违规报告: ```java @PostMapping("/api/csp-report") public void handleCspReport(@RequestBody String report) { log.warn("CSP violation: {}", report); // 记录到数据库或监控系统 } ``` ### 第二步:宽松策略 ``` Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' ``` ### 第三步:收紧策略 逐步移除 `unsafe-inline` 和 `unsafe-eval`,替换为 nonce 或 hash。 ### 第四步:严格策略 ``` Content-Security-Policy: default-src 'none'; script-src 'self' 'nonce-{random}'; style-src 'self' 'nonce-{random}'; img-src 'self'; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self' ``` ## 常见问题 ### 问题 1: 内联事件处理器 ```html Click Click document.getElementById("myBtn") .addEventListener("click", doSomething); ``` ### 问题 2: 第三方脚本 Google Analytics、Sentry 等第三方脚本需要在 CSP 中显式允许: ``` script-src 'self' https://www.googletagmanager.com https://browser.sentry-cdn.com; connect-src 'self' https://www.google-analytics.com https://sentry.io; ``` ### 问题 3: eval 和 new Function 某些库(如老版本模板引擎)依赖 eval。尽量升级或替换,实在不行才使用 `unsafe-eval`。 ## 测试工具 - **CSP Evaluator**:Google 提供的 CSP 策略评估工具 - **observatory.mozilla.org**:Mozilla 的安全头部检测 - **浏览器 DevTools Console**:CSP 违规会显示在控制台 ## 总结 CSP 是前端安全的关键防线,能有效防御 XSS 攻击。推荐使用 nonce 替代 unsafe-inline,通过 Report-Only 模式逐步收紧策略。虽然初始配置有一定工作量,但一旦建立,就能显著提升应用的安全等级。

← Back to Blog