【Security-Header】用CSP构建前端安全能力

作者: 康康 分类: Web安全,企业安全 发布时间: 2020-06-21 23:55

如果说有一个现成的防火墙,能够保护你的站点免受XSS攻击、运营商劫持、浏览器的流氓插件、用户环境的广告脚本注入、还能一定程度对抗爬虫和黑产脚本行为,是不是听起来很不错?

没错,Content-Security-Policy(简称CSP)就是这个现成的防火墙,你可以配置白名单规则,来让浏览器加载时阻断你不期望的恶意脚本,并把阻断事件上报给你。这一切都由浏览器来完成,你无需开发任何SDK, 只需要合理配置CSP规则,坐等收“违例报告”就可以了。本文旨在指导开发者给自己站点配置严格、合适的CSP策略,以达到治理XSS、阻断并感知第三方资源引用的目的。

一、CSP是什么

CSP是内容安全策略(Content-Security-Policy),是一个HTTP Header 头名称、W3C一个成熟标准。这其实并不是什么新鲜的东西,但是因其强大的功能和先进设计,仍然让现在的开发者直呼过瘾。其实质就是一个白名单制度,开发者可以在CSP中声明允许浏览器加载的资源列表,不在列表中的资源浏览器将不会加载。它的实现和执行全部由浏览器完成,保证我们的网站时只加载指定的资源。

这是一种防御XSS攻击的纵深防御技术。国外很多大厂都应用了该技术,当你打开谷歌地图、facebook、推特的首页,F12就能看到csp header:

推特的CSP Header

国内鲜有见到有配置CSP的站点,但不妨看看我在百度期间推进CSP的一些成果😊 ,直接浏览器打开好看视频、百度知道, F12就能看到:

haokan.baidu.com(好看视频)
zhidao.baidu.com(百度知道)
passport.baidu.com(百度账号系统)彩蛋:不妨想想圈出来的都有哪些作用

二、CSP的价值

  • 治理XSS漏洞。XSS漏洞可能导致蠕虫传播、帐号凭证泄漏、跳转到黄赌网站。而广告产品的XSS漏洞还会导致落地页被插入不受监管的广告 。 CSP-script-src等指令可以对产品页面内加载的js等资源进行约束,有效使规避因偶发xss漏洞导致的危害。
  • 阻止mixed-content。HTTPS站点中的HTTP资源可以被运营商或中间人劫持,用于广告注入、钓鱼。 block-all-mixed-content 指令可以对这类HTTP资源做阻断拦截并上报。提升用户浏览环境安全性
  • 阻止页面图片或样式篡改。style-src、img-src指令非常适合在论坛、富文本场景的产品中配置,可以有效规避样式或图片篡改。
  • 防点击劫持、Referrer泄露敏感信息等。X-Frame-Option以及Referrer-Policy的相关功能,都可以在CSP中集成一并进行声明。

在这个流氓浏览器、垃圾广告软件、运营商劫持盛行的年代,CSP可以有效阻止第三方资源加载、对抗浏览器隐私外泄、净化用户浏览环境,可能是日后web发展的一大趋势。这使得攻击者即使发现了漏洞,也没法注入第三方,除非还控制了列入CSP白名单的资源。 同时还能上报违例给开发者,可谓是在安全监控感知、SDL、黑产打击、数据隐私保护方面一举多得。

三、怎么配置CSP

下面以防治XSS为目的,介绍CSP基线配置。

1.配置CSP的流程

  1. 开发者先依据下面指导确定初版CSP,直接在代码路由的响应头加上Content-Security-Policy-Report-Only,这样如有非白名单的js资源被浏览器加载,浏览器就会异步post一个违例json给上报服务,但不会阻断拦截。
  2. 观察一段时间违例日志,没有误拦截后再将Content-Security-Policy-Report-Only 改为 Content-Security-Policy 即开启拦截,阻断第三方资源引用和XSS攻击。

2.CSP的配置基线

建议在以下基线规则的基础上制定,即可防御XSS

Content-Security-Policy:
object-src 'none';
script-src 'self' 'nonce-{random}' 'unsafe-inline' 'unsafe-eval'  'sha256-xxxx' 'report-sample' example.com:*  http://example.com/js  blob: ;
frame-src 'self' example.com;
base-uri 'self';    
report-uri https://report-to-your-domian   

其中object-src、script-src、frame-src base-uri、report-uri为指令名。’self’  ‘none’ 等为标志位,example.com为指令值。指令集彼此用分号隔,指令值彼此用英文空格隔开。

1. 确定指令名

  • 使用object-src、script-src、base-uri、frame-src、report-uri,这几个就足够可以阻止绝大多数XSS或脚本注入,其他指令名对于解决XSS帮助不大。
  • 不过出于产品安全与隐私保护角度,我们仍然鼓励开发者参考
    https://cloud.tencent.com/developer/chapter/13541 配置其他指令:论坛、商城、落地页等允许用户编辑富文本样式的产品可以考虑加入default-src或单独声明sytle-src、img-src、connect-src,来避免页面样式或图片被篡改、广告追踪、运营商劫持注入、流氓浏览器收集隐私。
  • 该头需要在返回HTML文档和json接口的HTTP Response Header处声明。在meta标签中设置不能上报违例信息,故不推荐。

2. 声明object-src

object-src  ‘none’  防止浏览器加载插件资源<object>,<embed>或<applet>标签。主要是防止Flash based xss。

3. 声明script-src

script-src  用于约束浏览器加载的脚本列表。

  • ‘self’ 该指令值指允许加载当前域的资源
  • ‘unsafe-inline’  该指令值允许内联脚本加载,这个指令不建议单独使用。
    • 开发者免不了在页面里会有内联的<script>标签,需要依据依据【内联脚本改造指引】进行改进,将内联脚本放入js文件中。如有内联事件,需要依据【内联事件改进指导】改进。这样就不必声明’unsafe-inline’。
    • 不能改进内联脚本的,建议在CSP头除了声明’unsafe-inline’, 原则上还须同时声明’nonce-{random}’或者’sha256-xxxx’ 来加白内联脚本。单独使用’unsafe-inline’会破坏CSP的XSS拦截功能(如弹框、跳转、内联js注入攻击不能被拦截),使得CSP形同虚设。不妨了解下【为什么不推荐单独使用unsafe-lnline】。
    • ‘nonce-{random}’ 指在CSP头和页面中<script>标签属性中都加入相同的nonce随机数,其值由服务后端每次响应时吐出。浏览器只加载nonce值与csp头中一致的内联脚本。 前端开发者在模版给内联脚本添加nonce占位符,可参考【webpack-nonce】或手动添加。后端给nonce占位符和CSP头加随机数 。
    • ‘sha256-xxxx’  指将开发者自己的内联<script>脚本中的代码块(不含<script></script>前导和后尾)计算其sha-256哈希后再base64编码,并在CSP头中声明以加白固定的内联代码。添加方法:可以使用【script哈希在线生成器
  • ‘unsafe-eval’   允许页面加载eval()、定时器等JavaScript函数,不使用的话应当去掉该标志位,使得CSP更严谨。
  • ‘report-sample’  指的是如有第三方js引用或者遭受XSS攻击会触发违例,浏览器会异步将违例的js代码前40个字节异步POST给 report-uri 对应的URL。可以用于定位和溯源。

4. 声明frame-src

frame-src ‘self’ 可以防止攻击者、运营商、浏览器通过注入其他iframe标签来收集信息或加载广告

5. 给script-src、frame-src添加白名单域名/源的指令值
此白名单域名(源) 应当秉承最小化范围原则 ,确保无用户可控的静态资源。通过https://cdn.xxxx.com/js 、*.example.com 、example.com:* 来实现加白路径、加白子域名、加白任意端口(80/443/8080),还有ServiceWorker使用的blob:协议。

6. 声明base-uri 

base-uri ‘self’  以防止攻击者更改URL相对位置来绕过CSP。

7. 利用report-uri 进行违例上报

  • 浏览器会异步将违例信息POST一个json给report-uri。违例信息会包含违例代码位置、触发XSS的URL 。 report-uri后可以声明多个URI
  • 建议先使用Content-Security-Policy-Report-Only头仅上报不拦截持续1周,以确保无误拦,再开启拦截

调试

可以使用【CSP Chrome 插件】来临时给自己的站点模拟添加的CSP,开发者可浏览页面并在console中观察效果,并进一步调整规则。

示例

这里结合业界领先网站,对script-src的组合做示范

1.推特(twitter.com): 涉及内联脚本,声明nonce加白(CSP2.0标准)。而浏览器识别到nonce会自动忽略unsafe-inline。保留unsafe-inline是顾及古老浏览器即便不兼容nonce也不会影响可用性。以下设置可以有效解决XSS漏洞。

Content-Security-Policy: script-src 'self'   'unsafe-inline' 'report-sample' https://*.twimg.com https://www.google-analytics.com 'nonce-ZjQ1OWIzMmEtNDgyZi00NzdiLTkyZTUtZjgzNWRjOWVkZjQ5'   

2.谷歌云控制面板( console.developers.google.com ):因涉及内联脚本中还会动态引入内联脚本,故加入【‘strict-dynamic’ 】(CSP3.0标准),可级联信任标签,浏览器识别到’strict-dynamic’后会自动忽略加白的白名单域。http: https:是出于可用性来兼容古老浏览器考虑。 以下设置也可以有效解决XSS漏洞。

content-security-policy:   script-src 'report-sample' 'nonce-3qE77FqMGPzZy+ZQBFJ8Pg' 'unsafe-inline'   'strict-dynamic' https: http: 'unsafe-eval';   

3.我的网站(notesus.cn):使用CSP2.0标准,因内联脚本固定,故使用sha-256来加白。也可有效解决XSS。

 Content-Security-Policy: script-src 'self' 'unsafe-inline' 'sha256-7zvvBFdtYp2Vr5yo9lVw1QDmdzOdG34+r8IHOTqX3DM=' 'sha256-hLc9U2cdQ6kejdQf+LEAdIw2u4VygoP/wDDXHTUQiOZ4=' 'sha256-e7Db97e1YeQHPAiN80jSQUwFO1YDc1yWaabve8fcBs8=' https://zz.bdstatic.com/linksubmit/push.js; object-src 'none'; base-uri 'self';frame-src 'self';report-uri /index.php?csp-report 

并且我的上报服务/index.php?csp-report 收到的原始违例信息:

{“csp-report”:{“document-uri”:”http://xxxxxxx.com/mock/csp4″,”referrer”:””,”violated-directive”:”script-src-elem”,”effective-directive”:”script-src-elem”,”original-policy”:”script-src ‘self’ nichang.cdn c.mipcdn.com ‘unsafe-eval’;report-uri /report-uri;”,”disposition”:”report”,”blocked-uri”:”http://xsspt.cn/ssss”,”status-code”:200,”script-sample“:””

四、日志分析

  1. 要发现XSS其实不难。 不妨想想内联XSS的触发会在违例中哪些字段留下痕迹,主流的XSS平台又存在什么特征。这里不再详细阐述。
  2. 黑灰产注入的脚本通常用什么做混淆?不妨想想混淆又有哪些共同特征?

五、影响浏览器生态

MIUI12的照明弹的出现,让各大互联网厂商不得不重视自己的APP隐私。如果机会允许,我也会做相同有影响力的事情。CSP日志中能够窥到国内外浏览器的生态:

  • 有些套壳浏览器疯狂收集用户浏览信息,还有各种浏览器插件收集页面敏感信息
  • 有些手机浏览器不仅不遵守CORS Credentials,还疯狂注入小广告
  • 有些运营商则伺机劫持HTTP注入流量套餐广告。
  • 有些杀毒软件喜欢在CSP策略注入自己的白名单以加白自家产品。

六、引用&参考

谷歌发表的CSP策略落地指导:https://csp.withgoogle.com/

OWASP发表的CSP指南 https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html

CSP的各指令详细解释指导-腾讯云开发者手册:https://cloud.tencent.com/developer/chapter/13541

chrome83支持加白某一类标签https://developers.google.com/web/updates/2020/05/nic83#trusted-types

MDN指导: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy

CSP检查器,可帮助开发者发现当前CSP的不足点-Google:https://csp-evaluator.withgoogle.com/

Chrome的CSP策略指导和代码改进指引:https://developer.chrome.com/extensions/contentSecurityPolicy

发表评论

电子邮件地址不会被公开。 必填项已用*标注