在介绍CSP之前,我们先先来了解一下什么是XSS攻击?
XSS攻击:一种常见的跨脚本web攻击方式,它通过向浏览器注入一段可执行的恶意脚本代码,并且被浏览器成功的执行来达到攻击的目的。一次XSS攻击可以获取到用户的联系方式,向用户发送诈骗信息,甚至可以可以通过SQL注入来攻击数据库
XSS攻击的形成条件:
- 向前端注入可执行的恶意代码
- 代码能够被浏览器成功的执行
为了防止XSS攻击,要采取很多措施,非常麻烦,就有人提出能不能从根本解决问题,浏览器自动禁止外部注入恶意脚本,这就是CSP的来历。CSP是在2008年由Mozilla的Sterne提出的浏览器安全框架,被设计为一个完整的框架来防御XSS和CSRF攻击,通常也可以用来控制app和扩展的权限
一:CSP简介:
csp实质就是白名单制度,由网页开发者设置哪些外部资源可以加载、执行,它的实现和执行全部由浏览器完成,开发者之需要配置,CSP大大增加了网页的安全性,攻击者即使发现了漏洞,也没办法注入脚本,除非还控制了一台列入白名单的可信主机,他直接在协议层就把一些存在安全隐患的用法默认干掉了,可以说是把同源策略发挥到了极致(可参考下图1)
https://img-blog.csdn.net/20171223144058534?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzY4NDYyMzQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
但是这样CSP也存在一些问题:
难部署,如果需要改动的话,改动较大;
实现成本高,他需要解析网站内部的script标签,可能会带来一些额外的模板引擎的性能成本
现在我这么说CSP的问题你可能不太理解,请抱着疑问耐心的往下看一看…
二:CSP的两种配置方法
1⃣️通过HTTP头信息的Content-Security-Policy字段
2⃣️通过网页的meta标签设置
代码如下:
<meta http-equiv="Content-Security-Policy" content="script-src 'self';object-src 'none';style-src cdn.example.org;child-src https">
我来解析一下上述的meta标签代码,CSP是做了如下配置:
script-src:只信任当前域名
object标签:不信任任何外来URL,即不加载任何资源
style-src: 只信任cdn.example.org third-party.org
child-src: 框架必须使用HTTPS协议加载
一旦启用之后,不符合CSP的外部资源就会被阻止加载!
当然这只是很小一部分的配置,仅仅配置这些还是不能够阻止XSS攻击的
三:详解CSP的限制选项
3.1 资源加载限制
script-src : 外部脚本
style-src:样式表
img-src: 图像
media-src: 媒体文件(音频和视频)
font-src: 字体文件
object-src: 插件(eg: flash)
child-src: 框架
frame-ancestors: 嵌入的外部资源,eg: <iframe>标签
connect-src: HTTP连接(通过XHR 、 WebSockets、EventSource等)
worker-src: worker脚本
manifest-src: manifest 文件
3.2 default-src:用来设置上面各个选项的默认值
Content-Security-Policy: default-src ‘self’
3.3 URL限制:
有时,网页会跟其他网页产生联系,这时也可以加以限制
frame-ancestors:限制嵌入框架的网页
base-uri:限制<base#href>
form-action:限制<form#action>
3.4 report-uri
有时,我们不仅希望防止XSS,还希望记录此类行为,report-uri就是用来告诉浏览器应该把注入行为报告发送给哪个网址
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
浏览器会使用POST方法,发送一个JSON对象,下面是一个例子
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/",
"blocked-uri": "http://evil.example.com/evil.js",
"violated-directive": "script-src 'self' https://apis.google.com",
"original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
}
}
四:选项值
每个限制选项可以设置以下几种值,这些值就构成了白名单
主机名:example.org,https://example.com:443
路径名:example.org/resources/js/
通配符:.example.org,://.example.com:(表示任意协议、任意子域名、任意端口)
协议名:https:、data:
关键字’self’:当前域名,需要加引号
关键字’none’:禁止加载任何外部资源,需要加引号
多个值也可以并列,用空格分隔。
Content-Security-Policy: script-src 'self' https://apis.google.com
如果同一个限制选项使用多次,只有第一次会生效。
# 错误的写法 script-src https://host1.com; script-src https://host2.com
# 正确的写法 script-src https://host1.com https://host2.com
如果不设置某个限制选项,就是默认允许任何值。
五、script-src 的特殊值
除了常规值,script-src还可以设置一些特殊值。注意,下面这些值都必须放在单引号里面。
‘unsafe-inline’:允许执行页面内嵌的<script>标签和事件监听函数
unsafe-eval:允许将字符串当作代码执行,比如使用eval、setTimeout、setInterval和Function等函数。
nonce值:每次HTTP回应给出一个授权token,页面内嵌脚本必须有这个token,才会执行
hash值:列出允许执行的脚本代码的Hash值,页面内嵌脚本的哈希值只有吻合的情况下,才能执行。
nonce值的例子如下,服务器发送网页的时候,告诉浏览器一个随机生成的token。
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
页面内嵌脚本,必须有这个token才能执行。
<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa> // some code </script>
除了script-src选项,nonce值和hash值还可以用在style-src选项,控制页面内嵌的样式表。
六、注意点
(1)script-src和object-src是必设的,除非设置了default-src。
因为攻击者只要能注入脚本,其他限制都可以规避。而object-src必设是因为 Flash 里面可以执行外部脚本。
(2)script-src不能使用unsafe-inline关键字(除非伴随一个nonce值),也不能允许设置data:URL。
下面是两个恶意攻击的例子。
<img src="x" onerror="evil()"> <script src="data:text/javascript,evil()"></script>
(3)必须特别注意 JSONP 的回调函数。
<script src="/path/jsonp?callback=alert(document.domain)//"> </script>
上面的代码中,虽然加载的脚本来自当前域名,但是通过改写回调函数,攻击者依然可以执行恶意代码。
七:XSS攻击的其他解决方案
1. 前端在进行校验的时候,对于特殊字符(eg:<>、'、;)严格控制输入,进行转义
2. 后端再次对提交的数据进行过滤,如果用户提交了恶意的数据或攻击进行屏蔽,但是像博客园、CSDN这样大型的IT交流平台,本身都是需要输入html标签的,可以通过白名单进行校验,允许使用确认安全的标签,其他都过滤掉
3. 安装第三方的防火墙,在一定程度上也会阻止xss攻击,eg: IUEditor,node环境也支持安装xss
八:总结
其实上述讲了很多关于CSP,我们也能了解到CSP的优缺点了,在大型集群上,比如QQ、微博平台,是不可能使用CSP来进行防御的,单单成本上来讲就是一笔不可想象的巨款。我认为CSP现在还处于一个理想者状态,但不能否认未来CSP能够杜绝XSS攻击的能力。