FrankKai.github.io
FrankKai.github.io copied to clipboard
内容安全策略CSP是什么?
当我们谈起如何防范web安全中的XSS攻击时,通常会说:浏览器引入了内容安全策略,也就是CSP(Content Security Policy),去解决XSS攻击的问题。
有人说,CSP的核心思想是让服务器决定浏览器能够加载哪些资源,相当于一个前端资源白名单。这样做的目的是抵御XSS攻击,提升前端安全性。
那么CSP到底什么呢? 这句对CSP的概括是否准确呢?
- CSP前言
- 面临的威胁
- 如何使用CSP
- 示例:常用的使用示例
- 测试你的策略
- 开启报告
- 违规报告语法
- 违规报告采样
- CSP指令指南
- 腾讯AlloyTeam两篇非常好的CSP文章
CSP前言
Content Security Policy(CSP)是一个检测和减轻确定类型攻击的内容安全层,这些确定攻击类型包括XSS(Cross Site Scripting)攻击和数据注入攻击。这些攻击可以造成网站的数据盗窃,网站污损和恶意软件安装。
CSP是完全的向后兼容的(除了CSP2.0版本有一些明显的在兼容性上的问题;更多细节可以看1.1章节)。 服务器实现了CSP而浏览器不支持的,浏览器可以正常工作,但是浏览器会忽略CSP,默认使用标准的web同源策略。如果网站没有提供CSP头,浏览器同样会使用标准的同源策略。
为了开启CSP,你需要配置的web服务器(Apache, Nginx) 去返回Content-Security-Policy HTTP头。(有时你可能会看到X-Content-Security-Policy头,但是这是一个老版本的头,无需关心)
或者,可以使用<meta>
标签去配置策略,例如<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*;child-src 'none'; ">
面临的威胁
缓解XSS攻击
设计CSP的一个重要原因就是缓解和报告XSS攻击。XSS利用浏览器对服务器接收的内容的信任发起攻击。因为浏览器信任内容源,所以恶意脚本在受害者的浏览执行,即使内容并不是来自于它应该来自的地方。
CSP通过指定浏览器的源,可以使得服务器管理者减少或者消除XSS发起的攻击。一个CSP兼容的浏览器会只接收在白名单域名下的资源文件,忽略其他脚本(内联脚本或者事件处理html属性)
还有一个最终的保护形式,全局禁止脚本执行可以使得站点上的所有脚本不执行。
缓解数据包嗅探攻击
除了限制哪些源可以加载内容以外,服务器还可以指定哪个协议和端口被使用;例如(来自一个理想的标准端口),一个服务器可以指定所有内容都通过HTTPS加载。一个完整的数据传输安全策略不仅仅包含HTTPS传输数据,也包括通过设置cookie的secure属性
并且自动重定向到HTTP页面到HTTPS页面。网站可以使用strict-Transport-Security
HTTP头去确保只通过加密通过去连接浏览器和服务器。
如何使用CSP
配置内容安全策略主要是通过给网页增加Content-Security-Policy
HTTP头,设置这个头的值可以控制用户端可以加载哪些资源。例如, 一个上传和展示图片的页面,需要允许任何地方的图片都可以展示,但是提交表单的时候需要限制到指定端口。 一个适当设计的内容安全策略可以阻止网站受到XSS攻击。这个文章将解释如何设置内容安全头。
指定你的策略
你可以使用Content-Security-Policy
HTTP头去设置策略,例如:
Content-Security-Policy: policy
policy是一个字符串,用于描述你的内容安全策略。
写一个策略
使用一系列策略指令来描述策略,每个策略指令都描述特定资源类型或策略区域的策略。您的策略应包括default-src策略指令,这是其他资源类型没有自己的策略时的后备(有关完整列表,请参阅default-src指令的说明)。策略需要包括default-src或script-src指令,以防止运行内联脚本以及阻止使用eval()。策略需要包括default-src或style-src指令,以限制从
示例:常用的使用示例
网站管理员想要所有的内容都来自自己的origin(排除子域)
Content-Security-Policy: default-src 'self'
网站管理员想要所有的内容来自一个可信域及其子域
Content-Security-Policy: default-src 'self' *.trusted.com
网站管理员想要允许web应用的用户在自己的内容中可以包含任意源的图片,但是限制音频,视频为指定的提供者,所有的脚本文件只能来源于部署了文件的机器
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
这里,默认内容只允许来自于当前文档源:
- 图片来自任意位置,*号通配符
- 媒体资源可以来源于media1.com和media2.com,不能来源于它们的子网站
- 可执行脚本只能来源于userscripts.example.com
一家在线银行的网站管理员想要确保所有的内容都是使用TLS加载的,为了抵御请求窃听
Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
一家在线商店的网站管理员想要在电子邮件中允许HTML,图片可以来自于任意源,但是禁止js或者其他有危险的内容
Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
注意script-src没有被特殊声明,这是因为在CSP这个例子中,已经设定了default-src 'self',这也就意味着这个网站加载的脚本只能来源于自己的服务器
测试你的策略
为了便于部署,CSP可以使用只读模式部署。策略不是强制的,但是任意违规都会报告给提供的URL。另外,仅报告只读头可以用于测试策略的未来修订版,而不用实际部署它。
可以使用Content-Security-Policy-Report-Only
HTTP头去设置策略:
Content-Security-Policy-Report-Only: policy
如果Content-Security-Policy-Report-Only
头和Content-Security-Policy
头在同一个响应中返回,两种策略都生效。Content-Security-Policy标头中指定的策略被强制执行,而Content-Security-Policy-Report-Only策略仅生成报告,但不强制执行。
开启报告
默认情况下,违规报告不会被发送。为了开启违规报告,你需要声明report-uri
策略指令,提供一个URI去接收传送报告:
Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi
当你需要设置服务器去接收报告的时候,服务器可以按照您认为合适的任何方式存储或者处理它们。
违规报告语法
违规报告JSON对象包含以下数据:
- blocked-uri 通过内容安全策略加载时被阻止的资源URI。如果被阻塞的URI来自一个不同的源而不是document-uri的时候,被阻塞的URI被截断为协议,主机和端口。
- disposition 无论是"enforce"或者"report",都依赖于Content-Security-Policy-Report-Only或者Content-Security-Policy头。
- document-uri 违规发生地方的文档url。
- effective-directive 强制执行导致违规的指令。
- original-policy Content-Security-Policy HTTP头设置的原始策略。
- referrer 发生违规的文档的referrer。
- script-sample 行内脚本,事件处理器,或者样式的前40行
- status-code 实例化全局对象资源的http状态码
- violated-directive 违反的策略部分的名称
违规报告采样
http://example.com/signup.html仅支持从cdn.example.com下载样式表
Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports
<!DOCTYPE html>
<html>
<head>
<title>Sign Up</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
... Content ...
</body>
</html>
{
"csp-report": {
"document-uri": "http://example.com/signup.html",
"referrer": "",
"blocked-uri": "http://example.com/css/style.css",
"violated-directive": "style-src cdn.example.com",
"original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
}
}
CSP指令指南
Content Security Policy请求头由一个或者多个指令组成,多个指令的话由冒号”;“分隔
default-src
default-src指令定义了加载资源(js,图片,css,字体,ajax请求,frame,h5资源)的默认策略。 不是所有指令都回退到default-src
default-src 'self' cdn.example.com;
script-src
定义js资源的有效路径。
script-src 'self' js.example.com;
style-src
定义css资源的有效路径。
style-src 'self' css.example.com;
img-src
定义图片资源的有效路径。
img-src 'self' img.example.com;
connect-src
应用与XMLHttpRequest(AJAX),WebSocket,fetch(),<a ping>
或EventSource。如果不允许会返回一个400状态码。
connect-src 'self';
font-src
定义字体的有效路径(通过@font-face加载)
font-src font.example.com;
object-src
定义插件的资源,例如<object><embed><applet>
object-src 'self';
media-src
定义音频和视频的有效资源,例如HTML5的<audio><video>
。
media-src media.example.com;
frame-src
定义可加载frame的资源。在CSP2.0中,不推荐frame-src,推荐child-src。CSP3.0也推荐使用child-src。
frame-src 'self';
sandbox
类似于frame sandbox属性。
sandbox allow-forms allow-scripts;
report-uri
CSP失败情况下报告的URI。CSP3.0推荐使用report-to指令。
report-uri /some-report-uri;
child-src
定义web worker和嵌入的浏览器上下文(例如frame,iframe)的资源
child-src 'self'
form-action
定义了HTML<form>
action的有效资源
form-action 'self'
frame-ancestors
<frame> <iframe> <object> <embed> <applet>
嵌入的资源。如果将这个设置为'none',等价于X-Frame-Options: DENY
frame-ancestors 'none';
plugin-types
定义插件的MIME type。
plugin-types application/pdf
base-uri
定义HTML的src白名单。
base-uri 'self';
report-to
report-to groupName;
worker-src
限制Worker,SharedWorker,ServiceWorker的URL。
worker-src 'none';
manifest-src
manifest-src 'none';
prefetch-src
prefetch和prerender的请求
prefetch-src 'none'
navigate-to
navigate-to example.com
腾讯AlloyTeam两篇非常好的CSP文章
XSS终结者-CSP理论与实践 《Csp Nonce – 守护你的 inline Script》
参考文章: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP https://content-security-policy.com/