XSS
XSS
,即 Cross Site Script
,中译是跨站脚本攻击;其原本缩写是CSS
,但为了和层叠样式(Cascading Style Sheet
)有所区分,因而在安全领域叫做XSS
。浅说 XSS 和 CSRF
XSS
攻击是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。
攻击者对客户端网页注入的恶意脚本一般包括 JavaScript
,有时也会包含HTML
和Flash
。有很多种方式进行XSS
攻击,但它们的共同点为:将一些隐私数据像cookie
、session
发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。
XSS
攻击可以分为3
类:反射型(非持久型)、存储型(持久型)、基于DOM
。
反射型
反射型XSS
只是简单地把用户输入的数据 “反射” 给浏览器,这种攻击方式往往需要攻击者诱使用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。
存储型
存储型 XSS
会把用户输入的数据 "存储" 在服务器端,当浏览器请求数据时,脚本从服务器上传回并执行。这种XSS
攻击具有很强的稳定性。
比较常见的一个场景是攻击者在社区或论坛上写下一篇包含恶意JavaScript
代码的文章或评论,文章或评论发表后,所有访问该文章或评论的用户,都会在他们的浏览器中执行这段恶意的 JavaScript
代码。
基于DOM
基于DOM
的XSS
攻击是指通过恶意脚本修改页面的DOM
结构,是纯粹发生在客户端的攻击。
XSS防御
只要我们的代码中不存在漏洞,攻击者就无从下手,XSS防御有如下方式。
HttpOnly 防止劫取 Cookie
HttpOnly
最早由微软提出,至今已经成为一个标准。浏览器将禁止页面的Javascript
访问带有 HttpOnly
属性的Cookie
。
上文有说到,攻击者可以通过注入恶意脚本获取用户的Cookie
信息。通常 Cookie
中都包含了用户的登录凭证信息,攻击者在获取到Cookie
之后,则可以发起 Cookie
劫持攻击。所以,严格来说,HttpOnly
并非阻止XSS
攻击,而是能阻止 XSS
攻击后的Cookie
劫持攻击。
输入检查
不要相信用户的任何输入。 对于用户的任何输入要进行检查、过滤和转义。建立可信任的字符和 HTML
标签白名单,对于不在白名单之列的字符或者标签进行过滤或编码。
在XSS
防御中,输入检查一般是检查用户输入的数据中是否包含<
,>
等特殊字符,如果存在,则对特殊字符进行过滤或编码,这种方式也称为 XSS Filter
。
而在一些前端框架中,都会有一份 decodingMap
, 用于对用户输入所包含的特殊字符或标签进行编码或过滤,如 <
,>
,script
,防止XSS
攻击:
输出检查
用户的输入会存在问题,服务端的输出也会存在问题。一般来说,除富文本的输出外,在变量输出到HTML
页面时,可以使用编码或转义的方式来防御XSS
攻击。例如利用 sanitize-html 对输出内容进行有规则的过滤之后再输出到页面中。
CSRF
CSRF
,即Cross Site Request Forgery
,中译是跨站请求伪造,是一种劫持受信任用户向服务器发送非预期请求的攻击方式。通常情况下,CSRF
攻击是攻击者借助受害者的 Cookie
骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。CSRF 攻击的应对之道
浏览器的 Cookie 策略
Cookie
是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。Cookie
主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 个性化设置(如用户自定义设置、主题等)
而浏览器所持有的Cookie
分为两种:
Session Cookie
(会话期 Cookie
):会话期 Cookie
是最简单的Cookie
,它不需要指定过期时间(Expires
)或者有效期(Max-Age
),它仅在会话期内有效,浏览器关闭之后它会被自动删除。
Permanent Cookie
(持久性Cookie
):与会话期 Cookie
不同的是,持久性Cookie
可以指定一个特定的过期时间(Expires
)或有效期(Max-Age
)。
res.setHeader('Set-Cookie', ['mycookie=222', 'test=3333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);
CSRF
攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于cookie
中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie
来通过安全验证。
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
攻击,拒绝该请求。
然而,这种方法并非万无一失。Referer
的值是由浏览器提供的,虽然 HTTP
协议上有明确的要求,但是每个浏览器对于Referer
的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer
值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。
事实上,对于某些浏览器,比如IE6
或 FF2
,目前已经有一些方法可以篡改Referer
值。如果 bank.example
网站支持 IE6
浏览器,黑客完全可以把用户浏览器的Referer
值设为以 bank.example
域名开头的地址,这样就可以通过验证,从而进行 CSRF
攻击。
在请求地址中添加 token 并验证
要抵御CSRF
,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于cookie
之中。可以在HTTP
请求中以参数的形式加入一个随机产生的token
,并在服务器端建立一个拦截器来验证这个token
,如果请求中没有token
或者token
内容不正确,则认为可能是CSRF
攻击而拒绝该请求。
在 HTTP 头中自定义属性并验证
这种方法也是使用token
并进行验证,和上一种方法不同的是,这里并不是把token
以参数的形式置于HTTP
请求之中,而是把它放到 HTTP
头中自定义的属性里。通过 XMLHttpRequest
这个类,可以一次性给所有该类请求加上csrftoken
这个HTTP
头属性,并把token
值放入其中。这样解决了上种方法在请求中加入token
的不便,同时,通过XMLHttpRequest
请求的地址不会被记录到浏览器的地址栏,也不用担心token
会透过Referer
泄露到其他网站中去。
然而这种方法的局限性非常大。XMLHttpRequest
请求通常用于 Ajax
方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。
另外,对于没有进行CSRF
防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest
请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。
网友评论