美文网首页微信小程序.NETCore氖酷
Content-Security-Policy的实战应用

Content-Security-Policy的实战应用

作者: 牧羊童鞋 | 来源:发表于2017-10-11 21:35 被阅读1660次

    今天在浏览微信页面的时候,发现他的script标签上都有个once属性,好奇之下查阅了一番,发现这个属性是和一个http header Content-Security-Policy有关,这个header不看不知道,一看吓一跳啊,一把利器啊

    1. 同源限制

    首先我们要知道web浏览器为了安全都有会同源限制,什么是同源限制?就是来自 https://mybank.com 的代码应仅能访问 https://mybank.com 的数据,而绝不被允许访问 https://evil.example.com。同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据,比如cookie/locaStoragy/IndexDB就遵守同源限制。XMLHettpRequest也是存在同源限制,相信只要开发过web的同学在ajax获取数据时都遇到过这个问题。

    同源限制可以一定程度上限制我们的用户信息不会被盗取,但是却没法防止我们的页面被插入不法分子的资源(js,img,css等),毕竟页面上带src的元素资源是不受同源限制的。这些页面上的牛皮鲜让人很讨厌,影响是极其恶劣的:会让我们的js监控误报、会影响用户体验、甚至隐私泄露,所以我们需要对src资源也作出一定的限制,这就得Content-Security-Policy来了

    2. Content-Security-Policy(内容安全政策,下文简称为CSP)

    • 主要作用

    了解一样东西,我们首先的知道他有啥用,没用不是浪费时间么,毕竟大家都在假装生活很忙的样子,作用呢主要有两点:

    1. 使用白名单的方式告诉客户端(浏览器)允许加载和不允许加载的资源。
    2. 向服务器举报这种强贴牛皮鲜广告的行为,以便做出更加针对性的措施予以绝杀。
    • 怎么用

    我们知道了好处还是很犀利的啊,这么好的东西怎么玩?其实也很简单,前面说到了他其实就是一个http header嘛,所以我们只需要在返回html页面的同时加上个response header 就行了,后面的script-src代表是一个指令,指示浏览器你只能加载我屁股后面那些规则下的js代码,其他的都一律拒绝。

    Content-Security-Policy: script-src 'self' https://apis.google.com
    

    你还可以通过元标记的方式使用:

    <meta http-equiv="Content-Security-Policy" content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'">
    
    • 指令

    前面说到script-src是一个指令,那就说明还有其他的指令罗,没有错,下面的都是指令,覆盖了web页面的所有资源

    base-uri: 用于限制可在页面的 <base> 元素中显示的网址。
    child-src: 用于列出适用于工作线程和嵌入的帧内容的网址。例如:child-src https://youtube.com 将启用来自 YouTube(而非其他来源)的嵌入视频。 使用此指令替代已弃用的 frame-src 指令。
    connect-src: 用于限制可(通过 XHR、WebSockets 和 EventSource)连接的来源。
    font-src: 用于指定可提供网页字体的来源。Google 的网页字体可通过 font-src https://themes.googleusercontent.com 启用。
    form-action: 用于列出可从 <form> 标记提交的有效端点。
    frame-ancestors: 用于指定可嵌入当前页面的来源。此指令适用于 <frame>、<iframe>、<embed> 和 <applet> 标记。此指令不能在 <meta> 标记中使用,并仅适用于非 HTML 资源。
    frame-src: 已弃用。请改用 child-src。
    img-src: 用于定义可从中加载图像的来源。
    media-src: 用于限制允许传输视频和音频的来源。
    object-src: 可对 Flash 和其他插件进行控制。
    plugin-types: 用于限制页面可以调用的插件种类。
    report-uri: 用于指定在违反内容安全政策时浏览器向其发送报告的网址。此指令不能用于 <meta> 标记,这就是举报电话
    style-src: 是 script-src 版的样式表。
    upgrade-insecure-requests: 指示 User Agent 将 HTTP 更改为 HTTPS,重写网址架构。 该指令适用于具有大量旧网址(需要重写)的网站。

    这么多指令都要写?写起来不是很麻烦,不是的。你只需要写自己要求限制的指令就行,没写的都会默认没有限制。

    你还可以通过指定一个 default-src 指令替换大部分指令的默认行为,也就说如果你写了default-src 指令,那其他没写的指令都会服从default-src 的规则。

    • 规则

    规则主要是罗列一些你信任的域名,除此之外还有四个关键词:

    none 表示不执行任何匹配。
    self'表示与当前来源(而不是其子域)匹配。
    unsafe-inline表示允许使用内联 JavaScript 和 CSS。
    unsafe-eval 表示允许使用类似 eval 的 text-to-JavaScript 机制。

    • once属性

    讲了这么多那和我一开始发现的那个script标签上的once属性有啥关系呢?首先说明不存在不正当*关系。主要是现代浏览器认为内联css和内联js都是应该被视为危险的行为,但是你总不能因为菜刀能杀人就不让百姓用菜刀了吧,所以开个口子吧。如果你在使用CSP策略的同时有确实需要使用内联css和js怎么办?用once+随机数的方式

    <script nonce=EDNnf03nceIOfn39fn3e9h3sdfa>
      //Some inline code I cant remove yet, but need to asap.
    </script>
    

    然后我们在CSP的白名单中加上

    Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
    

    这样你这段内联js就可以生效了

    补充说明

    CSP 1 在 Chrome、Safari 和 Firefox 中非常实用,但在 IE 10 中仅得到非常有限的支持。 您可以 在 canisue.com 上查看具体信息。CSP Level 2 在 Chrome 40 及更高版本中可用。 Twitter 和 Facebook 等大量网站已部署此标头(Twitter 的案例研究值得一读),并为您开始在自己的网站上进行部署制定了相应标准。

    实战效果

    我们加上CSP头部后,开启csp上报功能后发现,10分钟上报了几千条,这被强奸的厉害啊,所以加上这个头部就显得更加有必要了

    遇到的坑

    在应用CSP后,有用户反映访问我们的站点出现问题,我们发现用户获取到的meta头乱了,而且在里面发现了一个不是我们写的域名:local.adguard.com,一查发现adguard是款 vpn软件,他对我们meta头部进行修改,修改就算了,还修改错了。后面我们改成response header的方式,不使用meta了,发现他也会修改http的response header,但是没修改错,垃圾VPN害死人啊

    参考文章:

    同源限制 - 阮一峰
    内容安全政策 - Google

    相关文章

      网友评论

      • ly0985:很好,用cordova做ios一直遇到这个问题,最后看到meta标签才想到可能是这个问题,正好看到你和阮一峰的文章,然后可算是解决问题了,谢谢:+1:
        ly0985:@牧羊童鞋 小白一个,感谢大佬
        牧羊童鞋:@ly0985 很高兴能帮到你

      本文标题:Content-Security-Policy的实战应用

      本文链接:https://www.haomeiwen.com/subject/wseiextx.html