阅读 2170

嘿,前端的CSP & CSP如何落地,了解一下?

CSP(Content-Security-Policy)是一个HTTP response header, 它描述允许页面控制用户代理能够为指定的页面加载哪些资源, 可防止XSS攻击

使用方式:

Content-Security-Policy: 指令1 指令1的值1 指令1的值2 指令1的值3; 指令2 指令2的值1 指令2的值2
复制代码

调试工具: Chrome插件——modheader。通过随意设置响应头来测试CSP

MDN文档

简单过一遍常见的指令

获取资源相关的指令

font-src
frame-src
img-src
script-src
media-src
style-src
...等等,其他参考MDN
复制代码

这些src规定了页面只能加载里面所设置的font、iframe、img、script...这些资源,比如有一个html页面的response header是:

Content-Security-Policy: img-src a.b.c; script-src 'unsafe-inline' a.b.c; style-src 'self'
复制代码

表示只能加载来自a.b.c域的图片、a.b.c域的脚本和行内脚本(如<script>console.log(1)</script>)、只能加载自己域下的style

这些xx-src,一般常见的配置有:

host配置

可精确匹配也可通配符匹配:

https://*.qq.com
https://a.b.com
*.qq.com
www.qq.com
复制代码

最后,有一个通用化配置——default-src,你给了它什么值,其他几个指令就默认什么值。其他指令如果有设置,那自身的值会覆盖default-src的值

schema配置

data: => dataURI,比如base64
blob: => blob资源
http: => 顾名思义
https: => 顾名思义
...一般是这些比较多,其他参考MDN
复制代码

注意,要写冒号。为了防止误解,所以上面用 =>描述了。eg:

Content-Security-Policy: img-src http: data:; style-src 'self'
复制代码

self

只能加载自身相同的域资源,其他如data:blob:就不能了

unsafe-inline

行内,一般针对于style和script标签。没有这个,就不能使用行内标签了

上报指令

如果设置了上报指令的上报地址,当页面有加载不合法的资源,将会往那里上报。比如

Content-Security-Policy: img-src www.qq.com; report-uri https://a.b.c/report
复制代码

当设置这个header的页面加载www.qq.com之外的图片的时候,将会阻塞加载,并在控制台报错,再上报到https://a.b.c/report

上报的数据就是这些,浏览器帮你拼装好了。当然,随便写的路径肯定是404的,这个自己起一个服务器就可以收到这个上报

目前阶段,一般使用report-uri上报,用法是后面接上上报地址。report-to是另一个上报指令,功能更丰富,使用方式稍微麻烦一点

Content-Security-Policy: report-uri https://a.b.c/report
Content-Security-Policy: report-uri /current_page_report
复制代码

其他的指令比较简单,但使用场景可能不是很多,有兴趣去MDN看看

CSP如何在自己前端项目落地

第一阶段

使用Content-Security-Policy-Report-Only头而不是直接使用Content-Security-PolicyContent-Security-Policy-Report-Only顾名思义,只是上报,不会阻塞资源加载。因此页面改造第一步是先通过仅仅上报的头来观察一段时间,看看哪些资源哪些case是不符合CSP的,漏掉的加上,不合理的干掉

初始化资源指令,给default-src一个'self',让资源都默认走本地。其次通过其他方式改变header(我使用了浏览器插件的方式,比较简单暴力。其实还可以自己开个服务器做代理、本地起nginx加头等等方式都可以),观察控制台报错,再把漏掉的资源补齐,如cdn站点、base64的data:、第三方sdk、图片cos存储地址等都是最常见的case

补齐资源,让页面不再报错;一些是不太优雅或者有风险的case,自己再另外衡量要不要换另一种方式引入或者去掉

另外,如果有iframe、worker、websocket这些的,也需要配置一下CSP

第二阶段

观察一段时间后,自己的上报站点如果有CSP报错,那么去解决掉,然后继续观察一段时间重复同样的步骤,直到没有CSP错误。当上报站点再也没有CSP错误或者错误比较少能接受范围内,将Content-Security-Policy-Report-Only换成Content-Security-Policy再次上线

线上不可能也要人家装插件啊、代理啊,如何修改这个头

一般页面就在nginx上对html配response header

location  ~* .(html)$ {
	add_header Content-Security-Policy "img-src http: data:; style-src 'self'";
}
复制代码

如果是ssr项目或者前后端不分离项目,服务端直接setheader即可

如果是新需求可能涉及到新的资源引入怎么办

确定知道的源,新增header配置;不确定的最好自己设置一个中转服务,或者重新思考一下需求/技术方案合理性;实在没办法,需要删除default-src设置,并且img-src需要妥协一下了

如果有新页面上线且旧页面已经不使用report-only了怎么办

nginx配置一下,不同的页面使用不同的头

location  /a {
	add_header Content-Security-Policy "img-src http: data:; style-src 'self'";
}

location  /b {
	add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri https://a.b.c/report";
}
复制代码

服务端的话,判断一下页面路径,采用不同的setheader方式

最后

页面又安全一分了,心里踏实,起码可以防止很多很多低端攻击手法了。再回头翻翻网上那些经典的攻击手法和案例,是不是可以防掉很多了。不过还是有办法破解的。。。前面说了用什么来调试来着?有想法的,评论区留下自己的想法或者方案,一起交流一下吧