V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wilddog
V2EX  ›  SSL

关于 Web 安全, 99%的网站都忽略了这些

  •  6
     
  •   wilddog · 2015-10-13 20:22:34 +08:00 · 7106 次点击
    这是一个创建于 3334 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作者:肖光宇
    野狗科技联合创始人,先后在猫扑、百度、搜狗任职。技术栈较广,曾经致力于数据分析,异常检测领域,通过数学模型和机器学习解决用户输入和搜索广告中的反作弊难题。也曾做过 java 开发,熟悉从网络到前端的全部技术。
    公众订阅号: wilddogbaas
    野狗科技官方网站: https://www.wilddog.com

    Web 安全是一个如何强调都不为过的事情,我们发现国内的众多网站都没有实现全站 https ,对于其他安全策略的实践更是很少,本文的目的并非讨论安全和攻击的细节,而是从策略的角度引发对安全的思考和重视。

    1.数据通道安全

    http 协议下的网络连接都是基于明文的,信息很有可能被泄露篡改,甚至用户都不知道通信的对方是否就是自己希望连接的服务器。因此,信息通道安全有以下两个目标:

    • 身份认证
    • 数据不被泄漏和篡改

    幸运的是 https 解决了上述问题的(更多关于 https 的细节可以看下上一篇干货[扒一扒 https 网站的内幕][2])。理论上 https 是安全的,即使如此, https 依然应该被重视,因为理论上理论和实践是一样的,但实践中又是另外一回事。前段时间爆发的心血漏洞就是一个例子。

    2.浏览器安全

    https 解决了点到点的安全问题和身份认证问题,接下来会出现问题的地方就只有 2 个:浏览器和服务器,这个层面上的安全问题并没有 https 一样的银弹可以一次性解决。

    2.1 origin 源

    了解浏览器安全,有一个概念特别重要,那就是源(origin) 什么是源呢?

    • 相同的 HOST
    • 相同的协议
    • 相同的端口

    举栗子:

    源这个概念为甚这么重要,这要从同源策略说起。

    2.2 同源策略

    同源策略限制了一个源( origin )中加载文本或脚本与来自其它源( origin )中资源的交互方式。简单的说就是一个源的页面上的 js 只能访问当前源的资源,不能访问其他源的资源。那么资源是什么呢?

    • DOM
    • 通过 AJAX 请求的网络资源
    • Cookie
    • WebStorage , webSql
    • ...

    很显然,同源策略以源为单位,把资源天然分隔,保护了用户的信息安全。

    同源策略是一堵墙,然而墙并非不透风。有很多方法可以绕过同源策略让 javascript 访问其他源的资源。比如: JSONP :
    基于 iframe 的方法( iframe+window.name iframe+window.domain iframe+webMessage )
    CORS : 我认为只有 CORS 是"正当的"绕过同源策略的方法 同源策略是浏览器安全策略的基础,但同源策略面对很多攻击是无能为力的,比如 XSS

    2.3 XSS(Cross-Site Script)

    跨站脚本攻击,名字跟同源策略很像,事实上他们之间基本没有关系。跨站脚本攻击本质上是一种注入攻击(有兴趣了解更多注入攻击可以看 Injection Theory )。其原理,简单的说就是利用各种手段把恶意代码添加到网页中,并让受害者执行这段脚本。 XSS 的例子只要百度一下有很多。 XSS 能做用户使用浏览器能做的一切事情。可以看到同源策略无法保证不受 XSS 攻击,因为此时攻击者就在同源之内。

    XSS 攻击从攻击的方式可以分为:

    • 反射型
    • 存储型
    • 文档型

    这种分类方式有些过时,长久以来,人们认为 XSS 分类有以上三种,但实际情况中经常无法区分,所以更明确的分类方式可以分为以下两类:

    • client(客户端型)
    • server(服务端型)

    当一端 XSS 代码是在服务端被插入的,那么这就是服务端型 XSS ,同理,如果代码在客户端插入,就是客户端型 XSS 。

    2.4 防止 XSS 攻击--转义

    无论是服务端型还是客户端型 XSS ,攻击达成需要两个条件:

    • 代码被注入
    • 代码被执行

    其实只要做好无论任何情况下保证代码不被执行就能完全杜绝 XSS 攻击。详情可以看下 XSS (Cross Site Scripting) Prevention Cheat Sheet 这篇文章。
    这里简单说下结论:任何时候都不要把不受信任的数据直接插入到 dom 中的任何位置,一定要做转义。

    2.4.1 对于某些位置,不受信任的数据做转义就可以保证安全:

    • div body 的内部 html
    • 一般的标签属性值

    2.4.2 对于某些位置,即使做了转义依然不安全:

    • <script>中
    • 注释中
    • 表签的属性名名
    • 标签名
    • css 标签中

    2.4.3 使用 JSON.parse 而不是 eval,request 的 content-type 要指定是 Content-Type: application/json;

    2.4.4 如果链接的 URL 中部分是动态生成的,一定要做转义。

    2.5 HTML 转义:

    & --> &amp;
    < --> &lt;
    > --> &gt;
    " --> &quot;
    ' --> &#x27;
    / --> &#x2F;
    

    2.6 使用浏览器自带的 XSS-filter

    现代浏览器都对反射型 XSS 有一定的防御力,其原理是检查 url 和 dom 中元素的相关性。但这并不能完全防止反射型 XSS 。另外,浏览器对于存储型 XSS 并没有抵抗力,原因很简单,用户的需求是多种多样的。所以,抵御 XSS 这件事情不能指望浏览器。

    可以通过 http 头控制是否打开 XSS-filter,当然默认是打开的.X-XSS-Protection

    2.7 CSP(Content Security Policy)

    从原理上说防止 XSS 是很简单的一件事,但实际中,业务代码非常多样和复杂,漏洞还是时不时会出现。 CSP 并不是用来防止 XSS 攻击的,而是最小化 XSS 发生后所造成的伤害。事实上,除了开发者自己做好 XSS 转义,并没有别的方法可以防止 XSS 的发生。 CSP 可以说是 html5 给 Web 安全带来的最实惠的东西。 CSP 的作用是限制一个页面的行为不论是否是 javacript 控制的。

    如何引入 CSP 呢?

    2.7.1 通过 response 头

    //只允许脚本从本源加载 Content-Security-Policy: script-src 'self'
    

    2.7.2 通过 html 的 meta 标签

    //作用同上<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
    

    那么 CSP 除了限制 script-src 之外还能限制什么呢?

    base-uri:限制这篇文档的 uri ;
    child-src:限制子窗口的源(iframe 、弹窗等),取代 frame-src ;
    connect-src:限制脚本可以访问的源;
    font-src:限制字体的源;
    form-action:限制表单能够提交到的源;
    frame-ancestors:限制了当前页面可以被哪些页面以 iframe,frame,object 等方式加载;
    frame-src:deprecated with child-src,限制了当前页面可以加载哪些源,与 frame-ancestors 对应;
    img-src:限制图片可以从哪些源加载;
    media-src:限制 video,audio, source,track 能够从哪些源加载;
    object-src:限制插件可以从哪些源加载;
    sandbox:强制打开沙盒模式;

    可以看出, CSP 是一个强大的策略,几乎可以限制了所有能够用到的资源的来源。使用好 CSP 可以很大成都降低 XSS 带来的风险。另外, CSP 还提供一个报告的头 Content-Security-Policy-Report-Only ,使用这个头浏览器向服务器报告 CSP 状态,细节先不讨论。

    Content-Security-Policy-Report-Only:script-src'self';
                                  report-uri/csp-report-endpoint/
    

    CSP 目前有两版: CSP1 和 CSP2 。

    两版的支持状态可以在 http://caniuse.com/#search=csp 中查到。

    2.8 X-Frame-Options

    这是 response 头,现在正在使用,但以后可以被 CSP 的 frame-ancestors 取代。目前支持的状态比起 CSP frame-ancestors 要好,使用的方式:

    X-Frame-Options:DENY//这个页面不允许被以 frame 的方式加载

    X-Frame-Options:SAMEORIGIN//这个页面只允许同源页面加载 X-Frame-Options:<uri>
    //这个页面只能被特定的域加载

    2.9 Http-Only

    使用 Http-only 保护 cookie ,可以保证即使发生了 XSS ,用户的 cookie 也是安全的。使用 Http-only 保护的 cookie 是不会被 javascript 读写的。

    2.10 iframe 沙箱环境

    虽然有同源策略, iframe 的问题还是有很多的,比如各种利用 iframe 进行跨源。 HTML5 为 iframe 提供了安全属性 sandbox ,如果使用此属性, iframe 的能力将会被限制,细节我们将会在以后的文章中详细讨论。

    2.11 其他安全相关的 HTTP 头

    X-Content-Type-Options 阻止浏览器进行 content-type 嗅探。告诉浏览器相信此服务器下发的资源的类型,防止类型嗅探攻击。

    HPKP(Public Key Pinning)Public Key Pinning 是一个 response 头,用来检测一个证书的公钥是否发生了改变,防止中间人攻击。

    HSTS (HTTP Strict-Transport-Security) 强制使用 TSL 作为数据通道,在[扒一扒 HTTPS 网站的内幕][9]中也有详细介绍。

    3.HTML5 对 Web 安全的影响

    HTML5 带来了很多新的特性,让浏览器和 javascript 获得了更大的能力。然而能力越大,被攻破后的危险就越大。

    HTML5 对 XSS 的影响主要体现在:

    更大的攻击面, HTML5 带来来更多的标签和更多的属性, XSS 发生的可能性更大。
    更大的危害, HTML5 更多的资源可以被 XSS 利用。黑客可以利用浏览器的一切权限,比如本地存储, GEO , WebSocket , Webworker 。

    遗憾的是 HTML 并没有针止 XSS 和 XSRF 带来系统性解决方案。在这个前提下, CSP 变得非常重要,可以大大降低 XSS 后的危害。

    HTML5 时代实际对开发者提出来更高的要求,因为有更多的交互,更多的前端行为, HTML5 有更多的 API 。希望共勉,不做蒙古大夫,与广大的开发者一同提高中国互联网的用户体验!

    4.references

    安全相关的 HTTP 头
    https://www.owasp.org/index.php/List_of_useful_HTTP_headers

    同源策略
    https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

    CSP
    http://www.w3.org/TR/CSP/

    HPKP
    https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning

    w3c iframe element
    http://www.w3.org/TR/2011/WD-html5-20110525/the-iframe-element.html

    MDN web security
    https://developer.mozilla.org/en-US/docs/Web/Security

    XSS cheet sheet
    https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet

    野狗科技官网
    https://www.wilddog.com/

    第 1 条附言  ·  2015-10-13 20:55:42 +08:00
    难道这篇的标题不够拉风? +。+
    29 条回复    2017-06-03 16:21:20 +08:00
    wilddog
        1
    wilddog  
    OP
       2015-10-13 20:25:03 +08:00
    作者:肖光宇
    野狗科技联合创始人,先后在猫扑、百度、搜狗任职。技术栈较广,曾经致力于数据分析,异常检测领域,通过数学模型和机器学习解决用户输入和搜索广告中的反作弊难题。也曾做过 java 开发,熟悉从网络到前端的全部技术。
    公众订阅号: wilddogbaas
    野狗科技官方网站: https://www.wilddog.com
    dong3580
        2
    dong3580  
       2015-10-13 20:30:42 +08:00   ❤️ 1
    先收藏,我就想说 为什么那么多网站都是用户名密码明文 post 提交,还是 http...呵呵,
    wilddog
        3
    wilddog  
    OP
       2015-10-13 20:50:02 +08:00
    @dong3580 感谢
    ryd994
        4
    ryd994  
       2015-10-13 21:06:58 +08:00
    X-Content-Type-Option 是告诉浏览器验证 mime
    abelyao
        5
    abelyao  
       2015-10-13 21:19:22 +08:00 via iPhone
    @dong3580 因为前端加密就是自欺欺人,直接上 HTTPS 才是王道,连 HTTPS 都懒得部署的网站,你让他前端加密,顶多也就给你套一层 MD5 ,而对服务端来说收到一份不可逆的密码,也无法校验你的密码是否对方安全要求,如果是可逆的加密那直接看 JS 就跟皇帝的新衣一样。
    loading
        6
    loading  
       2015-10-13 21:46:27 +08:00 via iPhone
    这个只是个合集…感谢您的汗水
    wilddog
        7
    wilddog  
    OP
       2015-10-13 21:51:56 +08:00
    @loading 感谢您的回复
    crazycen
        8
    crazycen  
       2015-10-13 21:52:35 +08:00 via Android
    然而我并没有看完!
    dong3580
        9
    dong3580  
       2015-10-13 21:54:02 +08:00
    @abelyao
    你确定是前端问题?
    曾经我做后端的时候,做前端的不配合我做加密,然后我转做前端了。。。
    然而做后端的居然不被配合我 MD5 加密用户名密码验证码再 post ,
    然而还被鄙视是我太敏感了,
    可怕的不是一个人的无知,而是一群人的无知,
    认为前端 MD5 用户名密码验证到后端校验多此一举。
    crab
        10
    crab  
       2015-10-13 21:55:33 +08:00
    @abelyao 现在很多都是把密码通过 JS 内的 RSA 加密。
    abelyao
        11
    abelyao  
       2015-10-13 22:37:16 +08:00   ❤️ 1
    @dong3580 是是是,别人都无知。
    some0ne
        12
    some0ne  
       2015-10-13 22:46:16 +08:00
    @dong3580 确实是多此一举,因为你无法保证用户收到的 JS 是未被修改的。


    @crab JS 实现 RSA 加密也是一样的问题,你如何保证你收到的密钥是服务器发给你的密钥。
    crab
        13
    crab  
       2015-10-13 22:50:36 +08:00
    @some0ne 是不能保证啊。但比直接明文好多了。
    jackxy
        14
    jackxy  
       2015-10-13 23:06:55 +08:00
    @crab 确实比明文安全许多,但从理论上, https 是没有漏洞的,自己实现加密的办法一定会有漏洞。因为没办法建立 CA 证书链。
    jackxy
        15
    jackxy  
       2015-10-13 23:12:28 +08:00
    讨论安全问题一定要设置一个前提,
    比如 https 是安全的
    sha1 是无法被逆转的
    。。。
    在这个前提下讨论问题才有意义,不然会陷入无限的抬杠中
    其实做任何形式的加密都会对安全有提升,但标准组织已经造好了一套完美的轮子,我们照做就行。重复造了
    cooooooooool
        16
    cooooooooool  
       2015-10-14 00:06:45 +08:00
    收藏了,好文
    uuair
        17
    uuair  
       2015-10-14 00:16:07 +08:00
    刚在 segmentfault 看到这篇文章,原来作者也在这里。。。
    lincanbin
        18
    lincanbin  
       2015-10-14 00:22:32 +08:00
    感觉我是 1%诶,虽然用了 SSL ,但是登录时密码提交前我也 Hash 了一下再提交。
    X-Frame-Options 、 Http-Only 、 XSS 等等我也都做了。
    是不是自我感觉太良好?
    RitianZhao1988
        19
    RitianZhao1988  
       2015-10-14 01:56:14 +08:00
    mark
    wilddog
        20
    wilddog  
    OP
       2015-10-14 08:11:56 +08:00 via Smartisan T1
    @uuair 😄
    Citrus
        21
    Citrus  
       2015-10-14 08:40:02 +08:00 via iPhone
    文章不错,就是,发之前能仔细校对一下么?错别字和笔误太多了。。。
    dong3580
        22
    dong3580  
       2015-10-14 08:55:46 +08:00 via Android
    @some0ne
    有道理,
    laoyur
        23
    laoyur  
       2015-10-14 09:37:59 +08:00
    本站也是明文密码 post ,而且默认没开 https
    jackxy
        24
    jackxy  
       2015-10-14 11:42:03 +08:00
    赞 @lincanbin
    99%当然是为了标题党一下~~其实这些挺基本,但确实大多数工程师确实安全意识较弱
    jackxy
        25
    jackxy  
       2015-10-14 11:42:35 +08:00
    @Citrus 汗~多谢批评
    wilddog
        26
    wilddog  
    OP
       2015-10-14 13:32:25 +08:00
    jackxy 就是作者本人啦
    wangjinnan
        27
    wangjinnan  
       2015-10-14 13:59:23 +08:00
    mark
    wangjinnan
        28
    wangjinnan  
       2015-10-14 14:00:18 +08:00
    收藏
    78778443
        29
    78778443  
       2017-06-03 16:21:20 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1132 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:17 · PVG 03:17 · LAX 11:17 · JFK 14:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.