CSP(Content Security Policy),内容安全策略,是浏览器厂商为了缓解很大一部分潜在的 XSS 问题而引入的一个安全层,用来取代之前的 X-XSS-Protection
。两者相比,绝大多数浏览器已经支持 CSP,因而 X-XSS-Protection
已经被废弃了,作为了解可以看 MDN 文档
使用
CSP 策略可以在两处地方添加,一处是 HTML 页面中的 meta 标签,另一处是在 HTTP Response Header 中
Meta 标签
<meta http-equiv="content-security-policy" content="script-src 'self'; object-src 'self'">
<meta http-equiv="content-security-policy-report-only" content="script-src 'self'; object-src 'self'; report-uri 'https://test.com/report'">
content-security-policy
和 content-security-policy-report-only
的区别在于 content-security-policy
会限制不符合 CSP 策略的行为,而 content-security-policy-report-only
不会进行限制,而是报告不符合 CSP 策略的行为
HTTP Response Header
和 Meta 标签添加 CSP 策略的方式其实差不多,只是策略是写在 HTTP Response Header 中而已。实际上更加推荐是把 CSP 策略写在 HTTP Response Header 的,这样更加方便于维护。这里以 Caddy 为例
header / Content-Security-Policy "script-src 'self'; object-src 'self'"
header / Content-Security-Policy-Report-Only "script-src 'self'; object-src 'self'; report-uri 'https://test.com/report'"
策略
-
base-uri
:用于限制<base>
元素中显示的网址 -
child-src
:用于列出适用于工作线程和嵌入的帧内容的网址。例如:child-src https://youtube.com
将启用来自 YouTube(而非其他来源)的嵌入视频 -
connect-src
:用于限制可(通过 XHR,WebSockets,Fetch 和 EventSource)连接的来源。 -
font-src
:用于指定可提供网页字体的来源 -
form-action
:限制 <form> 提交的地址 -
frame-ancestors
:指定可嵌入当前页面的来源。此指令适用于<frame>
,<iframe>
,<embed>
和<applet>
-
img-src
:限制允许加载图像的来源 -
media-src
:限制允许传输视频和音频的来源 -
object-src
:限制 Flash 或其他插件的 src -
plugin-types
:限制页面可以调用的插件种类 -
report-uri
和report-to
:上报数据地址,report-uri
被废弃,但是不是全部浏览器都支持report-to
,所以建议两个都写 -
style-src
:限制样式表来源
您可以通过指定一个 default-src
指令来设置默认合法的来源。不过下面这些策略不受 default-src
的影响
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
来源
来源这块不单单可以填写实际的域名,还有一些关键词可以使用
-
none
:不限制来源 -
self
:与当前来源(而不是其子域)匹配 -
unsafe-inline
:允许使用内联 JavaScript 和 CSS -
unsafe-eval
:允许使用类似 eval 的 text-to-JavaScript 机制
Nonces 和 Hashes
在 CSP1 中,inline 资源要么全部允许,要么全部不允许。在实际开发中影响还是比较大的,虽然禁用 inline 资源确实能很有效的防御 XSS。所以 CSP2 引入了 Nonces 和 Hashes
Nonces 用于指定 inline 资源的序号(base64 编码后的随机数),只有指定了序号的 inline 资源来可以被执行
Content-Security-Policy: script-src 'nonce-1'
<script nonce="1">alert(0);</script>
Hashes 则是将 inline 资源直接做摘要签名,签名规则与 Subresource Integrity 一致,支持的算法有 SHA-256,SHA-512 等。同样摘要签名一样要做 base64 加密
echo -n 'alert(0);' | openssl dgst -sha256 -binary | openssl enc -base64 -A
Content-Security-Policy: script-src 'sha256-d3ii1Pel57UO62xosCMNgTaZJhJa87Gd/X6e7UdlEU8='
<script>alert(0);</script>
Nonces 方案使用起来比较简单,而 Hashes 方案相对安全许多
report
如果设置了 `report-uri` 或 `report-to`,那么当有不符合策略的行为出现时,就会往设置的 URI 地址 发送一个 POST 请求,具体数据大概如下所示
{
"csp-report": {
"document-uri": "http://127.0.0.1:9000/",
"referrer": "",
"violated-directive": "font-src",
"effective-directive": "font-src",
"original-policy": "default-src 'self' ; report-uri http://127.0.0.1:9000/report.php",
"disposition": "enforce",
"blocked-uri": "data",
"status-code": 200,
"script-sample": ""
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。