1.概念
XSS:Cross Site Script,中译是跨站脚本攻击
CSRF:Cross-site request forgery,中文为跨站请求伪造
XSS 攻击是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。
CSRF是一种劫持受信任用户向服务器发送非预期请求的攻击方式。通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。
2.XSS
攻击者对客户端网页注入的恶意脚本一般包括 JavaScript,有时也会包含 HTML 和 Flash。有很多种方式进行 XSS 攻击,但它们的共同点为:将一些隐私数据像 cookie、session 发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。
XSS攻击可以分为3类:反射型(非持久型)、存储型(持久型)、基于DOM。
1.反射型
这种攻击方式往往需要攻击者诱使用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,当用户点击恶意链接时,页面跳转到攻击者预先准备的页面,会发现在攻击者的页面执行了 js 脚本:
这样就产生了反射型 XSS 攻击。攻击者可以注入任意的恶意脚本进行攻击,可能注入恶作剧脚本,或者注入能获取用户隐私数据(如cookie)的脚本,这取决于攻击者的目的。
总结就是:用户点击一个恶意链接时候,跳转到攻击者预先准备好的页面,在这个页面攻击者可以注入恶作剧脚本,或者注入可以获取用户隐私数据(如cookie)的脚本等
2.存储型
存储型 XSS 会把用户输入的数据 “存储” 在服务器端,当浏览器请求数据时,脚本从服务器上传回并执行。这种 XSS 攻击具有很强的稳定性。
比较常见的一个场景是攻击者在社区或论坛上写下一篇包含恶意 JavaScript 代码的文章或评论,文章或评论发表后,所有访问该文章或评论的用户,都会在他们的浏览器中执行这段恶意的 JavaScript 代码。
总结:攻击者故意输入带有攻击性脚本,保存到服务器,每当有其他用户访问,就会指向这段恶意脚本
可以看下图理解,用户输入攻击性脚本上传,其他用户访问地址时,执行恶意脚本。
https://user-images.githubusercontent.com/7871813/42720476-eb71a5c8-8759-11e8-8763-eb08b3480201.gif
3.基于DOM
基于 DOM 的 XSS 攻击是指通过恶意脚本修改页面的 DOM 结构,是纯粹发生在客户端的攻击。
DOM型 XSS其实是一种特殊类型的反射型 XSS,它是基于 DOM文档对象模型的一种漏洞。可以通过 DOM来动态修改页面内容,从客户端获取 DOM中的数据并在本地执行。
可以看图理解:
https://user-images.githubusercontent.com/7871813/42721109-cb7ce572-8766-11e8-96d9-9ada8a787827.gif
3.XSS攻击的防范
现在主流的浏览器内置了防范 XSS 的措施,例如 CSP。但对于开发者来说,也应该寻找可靠的解决方案来防止 XSS 攻击。
1.HttpOnly防止劫取Cookie
众说周知,Cookie 在浏览器里可以保存一些例如 tokenId 等的一些控制系统登 录状态的数据。
Cookie 实际上是指小量信息,是由 Web 服务器创建的,将信息存储在用户计算机上的文件。一般习惯用其复数形式 Cookies,指某些网站为了辨别用户身份(tookenid)、进行 Session 跟踪而存储在用户本地终端上的数据(Cookie核心知识点),而这些数据通常会经过加密处理。
有些Cookie 是有限制的,一旦超过时间限制,就会被系统删除。很多人担心Cookie 会泄露用户的一些信息。但这是多余的,Cookie 是不能通过跨域来访问的,还有一些对象是不能脱离Cookie 来实现的,比如Session。这里还有一个点,就是客户端Cookie 数量最多为300个,每个不能超过4kb, 每个web站点设置的cookie 数量不能超过20个。
一般来说,只有服务器操作Cookie 才能保证一些必要的安全。但有时候,可能需要前端来增删改查 Cookie, 这个时候咱们的主角出现了——HttpOnly(๑•̀ㅂ•́) ✧.
HttpOnly是包含在Set-Cookie HTTP响应头文件中的附加标志。生成cookie时使用HttpOnly标志有助于降低客户端脚本访问受保护cookie的风险(如果浏览器支持)。
这个意思就是说,如果某一个Cookie 选项被设置成 HttpOnly = true 的话,那此Cookie 只能通过服务器端修改,Js 是操作不了的,对于 document.cookie 来说是透明的。话不多说,直接上图:
以 Google 翻译为例子,初次打开时,Cookie里面是这样的一共有4条记录,注意第二个最右侧倒数第三个字段有一个√, 这个对勾表明这条记录是 HttpOnly = true 的,对于Js,你是拿不到的。我们来试一下:
果不其然,Js获取Cookie 的时候就会跳过HttpOnly = true 的Cookie 记录。当然,既然拿不到,那就跟别说删改了。
上文有说到,攻击者可以通过注入恶意脚本获取用户的 Cookie 信息。通常 Cookie 中都包含了用户的登录凭证信息,攻击者在获取到 Cookie 之后,则可以发起 Cookie 劫持攻击。所以,严格来说,HttpOnly 并非阻止 XSS 攻击,而是能阻止 XSS 攻击后的 Cookie 劫持攻击。
参考文章:https://zhuanlan.zhihu.com/p/36197012
2.输入检查
不要相信用户的任何输入。 对于用户的任何输入要进行检查、过滤和转义。建立可信任的字符和 HTML 标签白名单,对于不在白名单之列的字符或者标签进行过滤或编码。
3.输出检查
用户的输入会存在问题,服务端的输出也会存在问题。一般来说,除富文本的输出外,在变量输出到 HTML 页面时,可以使用编码或转义的方式来防御 XSS 攻击。例如利用 sanitize-html 对输出内容进行有规则的过滤之后再输出到页面中。
4.CSRF
通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。
浏览器的Cookie策略
Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次象同一服务器再次发起请求时被携带并发送到服务器上。Cookie主要用于以下三个方面:
1.会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
2.个性化设置(如用户自定义设置、主题等)
3.浏览器行为跟踪(如跟踪分析用户行为等)
而浏览器所持有的 Cookie 分为两种:
1.Session Cookie(会话期 Cookie):会话期 Cookie 是最简单的Cookie,它不需要指定过期时间(Expires)或者有效期(Max-Age),它仅在会话期内有效,浏览器关闭之后它会被自动删除。
2.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;']);
上述代码创建了两个 Cookie:mycookie 和 test,前者属于会话期 Cookie,后者则属于持久性 Cookie。当我们去查看 Cookie 相关的属性时,不同的浏览器对会话期 Cookie 的 Expires 属性值会不一样:
Firefox:
Chrome:
通过Cookie进行CSRF攻击
简单点说,CSRF攻击就是 攻击者利用受害者的身份,以受害者的名义发送恶意请求。与XSS(Cross-site scripting,跨站脚本攻击)不同的是,XSS的目的是获取用户的身份信息,攻击者窃取到的是用户的身份(session/cookie),而CSRF则是利用用户当前的身份去做一些未经过授权的操作。
5.CSRF攻击的防范
当前,对 CSRF 攻击的防范措施主要有如下几种方式。
要完成一个CSRF攻击,必须具备以下几个条件:
1.受害者已经登录到了目标网站(你的网站)并且没有退出
2.受害者有意或者无意的访问了攻击者发布的页面或者链接地址
整个步骤大致是这个样子的:
1.用户小明在你的网站A上面登录了,A返回了一个session ID(使用cookie存储)
2.小明的浏览器保持着在A网站的登录状态,事实上几乎所有的网站都是这样做的,一般至少是用户关闭浏览器之前用户的会话是不会结束的
3.攻击者小强给小明发送了一个链接地址,小明打开了这个地址,查看了网页的内容
4.小明在打开这个地址的时候,这个页面已经自动的对网站A发送了一个请求,这时候因为A网站没有退出,因此只要请求的地址是A的就会携带A的cookie信息,也就是使用A与小明之间的会话
5.这时候A网站肯定是不知道这个请求其实是小强伪造的网页上发送的,而是误以为小明就是要这样操作,这样小强就可以随意的更改小明在A上的信息,以小明的身份在A网站上进行操作
1.验证码
验证码被认为是对抗 CSRF 攻击最简洁而有效的防御方法。
从上述示例中可以看出,CSRF 攻击往往是在用户不知情的情况下构造了网络请求。而验证码会强制用户必须与应用进行交互,才能完成最终请求。因为通常情况下,验证码能够很好地遏制 CSRF 攻击。
但验证码并不是万能的,因为出于用户考虑,不能给网站所有的操作都加上验证码。因此,验证码只能作为防御 CSRF 的一种辅助手段,而不能作为最主要的解决方案。
2.Referer Check
根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。通过 Referer Check,可以检查请求是否来自合法的"源"。
比如,如果用户要删除自己的帖子,那么先要登录 www.c.com,然后找到对应的页面,发起删除帖子的请求。此时,Referer 的值是 http://www.c.com;当请求是从 www.a.com 发起时,Referer 的值是 http://www.a.com 了。因此,要防御 CSRF 攻击,只需要对于每一个删帖请求验证其 Referer 值,如果是以 www.c.com 开头的域名,则说明该请求是来自网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是 CSRF 攻击,可以拒绝该请求。
针对上文的例子,可以在服务端增加如下代码:
if (req.headers.referer !== 'http://www.c.com:8002/') {
res.write('csrf 攻击');
return;
}
Referer Check 不仅能防范 CSRF 攻击,另一个应用场景是 “防止图片盗链”。
3.添加token验证
CSRF 攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 Cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 Cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
总结:
XSS:跨站脚本(Cross-site scripting,通常简称为XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
CSRF:跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
简单点说,CSRF攻击就是 攻击者利用受害者的身份,以受害者的名义发送恶意请求。XSS的目的是利用恶意脚本获取用户的身份信息/进行恶作剧,攻击者窃取到的是用户的身份(session/cookie)等操作,而CSRF则是利用用户当前的身份去做一些未经过授权的操作。
最后,总结一下 XSS 攻击和 CSRF 攻击的常见防御措施:
防御 XSS 攻击
防御 CSRF 攻击
参考文章:
https://github.com/dwqs/blog/issues/68
https://segmentfault.com/a/1190000008505616
https://www.jianshu.com/p/64a413ada155
https://juejin.im/post/5bad9140e51d450e935c6d64
https://juejin.im/post/5bc009996fb9a05d0a055192
https://www.cnblogs.com/lovesong/p/5233195.html
https://developer.mozilla.org/zh-CN/docs/Glossary/Cross-site_scripting
https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/index.html
https://segmentfault.com/a/1190000007059639
https://www.zhihu.com/question/34445731
https://blog.tonyseek.com/post/introduce-to-xss-and-csrf/
https://xwjgo.github.io/2017/10/26/XSS和CSRF/
http://jartto.wang/2017/12/15/xss-and-csrf/