XSS
XSS:跨站脚本(Cross-site scripting)
XSS:脚本中的不速之客
XSS 全称“跨站脚本”,是注入攻击的一种。其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文本。这时服务器端如果没有过滤或转义掉这些脚本,作为内容发布到了页面上,其他用户访问这个页面的时候就会运行这些脚本。
运行预期之外的脚本带来的后果有很多中,可能只是简单的恶作剧——一个关不掉的窗口:
while (true) {
alert("你关不掉我~");
}
CSRF
CSRF:跨站请求伪造(Cross-site request forgery)
CSRF:冒充用户之手
跟XSS
攻击一样,存在巨大的危害性,你可以这样来理解:
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。 如下:其中Web A
为存在CSRF
漏洞的网站,Web B
为攻击者构建的恶意网站,User C
为Web A
网站的合法用户。
CSRF攻击攻击原理及过程如下:
csrf.jpg- 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
- 在用户信息通过验证后,网站A产生
Cookie
信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A; - 用户未退出网站A之前,在同一浏览器中,打开一个
TAB
页访问网站B; - 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
- 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带
Cookie
信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie
信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
防御CSRF攻击:
目前防御 CSRF
攻击主要有三种策略:
- 验证
HTTP Referer
字段
根据
HTTP
协议,在HTTP
头中有一个字段叫Referer
,它记录了该HTTP
请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory
,用户必须先登陆bank.example
,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的Referer
值就会是转账按钮所在的页面的 URL,通常是以bank.example
域名开头的地址。而如果黑客要对银行网站实施CSRF
攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的Referer
是指向黑客自己的网站。因此,要防御CSRF
攻击,银行网站只需要对于每一个转账请求验证其Referer
值,如果是以bank.example
开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer
是其他网站的话,则有可能是黑客的CSRF
攻击,拒绝该请求。
这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心CSRF
的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查Referer
的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。
然而,这种方法并非万无一失。Referer
的值是由浏览器提供的,虽然HTTP
协议上有明确的要求,但是每个浏览器对于Referer
的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证Referer
值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,比如IE6
或FF2
,目前已经有一些方法可以篡改Referer
值。如果bank.example
网站支持IE6
浏览器,黑客完全可以把用户浏览器的Referer
值设为以bank.example
域名开头的地址,这样就可以通过验证,从而进行CSRF
攻击。
即便是使用最新的浏览器,黑客无法篡改Referer
值,这种方法仍然有问题。因为Referer
值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心Referer
值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供Referer
。当他们正常访问银行网站时,网站会因为请求没有Referer
值而认为是CSRF
攻击,拒绝合法用户的访问。
- 在请求地址中添加
token
并验证
CSRF
攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于cookie
中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的cookie
来通过安全验证。要抵御CSRF
,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于cookie
之中。可以在HTTP
请求中以参数的形式加入一个随机产生的token
,并在服务器端建立一个拦截器来验证这个token
,如果请求中没有token
或者token
内容不正确,则认为可能是CSRF
攻击而拒绝该请求。
这种方法要比检查Referer
要安全一些,token
可以在用户登陆后产生并放于session
之中,然后在每次请求时把token
从session
中拿出,与请求中的token
进行比对,但这种方法的难点在于如何把 token 以参数的形式加入请求。对于GET
请求,token
将附在请求地址之后,这样 URL 就变成http://url?csrftoken=tokenvalue
。 而对于POST
请求来说,要在 form 的最后加上<input type=”hidden” name=”csrftoken” value=”tokenvalue”/>
,这样就把 token 以参数的形式加入请求了。但是,在一个网站中,可以接受请求的地方非常多,要对于每一个请求都加上token
是很麻烦的,并且很容易漏掉,通常使用的方法就是在每次页面加载时,使用javascript
遍历整个dom
树,对于dom
中所有的 a 和form
标签后加入token
。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的html
代码,这种方法就没有作用,还需要程序员在编码时手动添加token
。
该方法还有一个缺点是难以保证token
本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上token
,黑客可以在自己的网站上得到这个token
,并马上就可以发动CSRF
攻击。为了避免这一点,系统可以在添加token
的时候增加一个判断,如果这个链接是链到自己本站的,就在后面添加token
,如果是通向外网则不加。不过,即使这个csrftoken
的形式附加在请求之中,黑客的网站也同样可以通过Referer
来得到这个token
值以发动CSRF
攻击。这也是一些用户喜欢手动关闭浏览器Referer
功能的原因。
- 在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过
XMLHttpRequest
这个类,可以一次性给所有该类请求加上csrftoken
这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过XMLHttpRequest
请求的地址不会被记录到浏览器的地址栏,也不用担心token
会透过Referer
泄露到其他网站中去。
然而这种方法的局限性非常大。XMLHttpRequest
请求通常用于Ajax
方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行CSRF
防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为XMLHttpRequest
请求,这样几乎是要重写整个网站,这代价无疑是不能接受的
网友评论