前言

对于一个影子杀手而言,总能杀人于无形。前端也有影子杀手,它总是防不胜防地危害着你的网站

本篇打算介绍一些前端的影子杀手们——XSS和CSRF。或许,你对它恨之入骨;又或者,你运用的得心应手。恨之入骨,可能是因为你的网站被它搞得苦不堪言;得心应手,可能是因为你从事这项工作,每天都在和此类问题打交道。那我们今天就来了解它,防御它。如果你喜欢我的文章,欢迎评论,欢迎Star~。欢迎关注我的github博客

正文

注:在开始正文之前,先声明一下,所有的实验环境均为本地搭建——DVWA。

影子杀手们,由来已久,几乎伴随着整个互联网的发展。历史的潮流,总是值得去考究,去深思的。可能在十年之前,这些问题层出不穷;随着开发者安全意识的提高,总是多多少少可以避免的。那么,我们就先来看看,今天的第一位主角——XSS。

第一位主角——XSS

记得在学校的时候,玩过CTF,应对类似于XSS等网络漏洞,总是会有固定的套路。今天我们也来了解了解这些套路。

概述

XSS的全名叫做Cross-site Scripting。不知你可否会有个疑问,老外都喜欢将英文缩写,但是为什么这个缩写却是XSS呢?因为只能怪它来的晚咯,被css抢先一步^_^。不过没关系,并不阻碍我们记忆它。

XSS是一种代码注入类攻击,它允许攻击者在其他人的电脑上面执行恶意的脚本代码。往往XSS并不需要攻击者去直接攻击受害者的浏览器。攻击者可以利用网站的漏洞,将这一段恶意代码提交。然后,通过网站去传递给受害者,同时窃取受害者的信息等。

我们可以先看一个简单的例子:

或许,你会好奇,我应该怎么去运用网站的漏洞,那我们先来看一张图:

这是一个评论框,然后我们可以在其中输入:

然后,你提交这条信息,如果该网站没有做防护(例如:过滤),那么,你所在的页面会跳出如下画面:

看了这个信息,或许你已经意识到了它的危害。因为如果可以这样子随意的运行js脚本,对于你客户端的信息(例如:cookie)将统统被窃取。

回到我们的话题,在看到xss的基本效果之后,你会认为JavaScript是危险的吗?

其实不然,真正的JavaScript是运行在比较严格的环境下面,并不会对操作系统或者其他应用造成伤害。不信的话,你可以打开控制台,在里面随意尝试,你会发现你并没有造成任何危害。那么,我们所谓的XSS的严重性,是吹的吗?

那就更加不是了。首先,我们要申明的是——何为恶意代码?恶意代码的叫法,并不是因为它本身是有危害的,而是它的意图是对使用者有害的。我们可以来看看,何为对使用者有害?例子:

  1. JavaScript对于用户的私密信息进行读取(例如:cookies)。
  2. JavaScript可以通过XMLHttpRequest发送任意的信息到任意的服务器上
  3. JavaScript可以修改当前页面中的任意DOM元素

这些行为,如果是不善的人所为,那么,将对使用者造成不可估量的损失。

XSS中的角色扮演

XSS整个流程中,会出现不同的角色。演员表可分为:网站、受害者、攻击者。

网站,通常是指那些会被受害者访问的HTML页面。

受害者,指的是那些访问网站的普通用户

攻击者,则是那些躲在阴暗角落,敲击着键盘的恶意用户。通常,攻击者还会具备一台自己的服务器,用来接收发送过来的用户信息。

整个流程图,如下:

整个流程中,演员都是必须的环节,不然整个攻击都无法完成。可从图中看出4个步骤:

  1. 攻击者选取一个具备漏洞的网站,在其数据库插入恶意代码
  2. 用户向网站服务器请求这个被注入的网站
  3. 网站服务器响应用户请求,并发送给用户已被修改的网站
  4. 用户完成访问,同时注入的恶意代码执行,将用户的cookie发送给攻击者服务器

希望你对这幅流程图多看几眼,因为它也将会是我们后续防御XSS的先决条件。之后,我们来看看XSS的分类情况

分类

XSS的目标是在受害者的浏览器中执行恶意代码。而实现这一目标,往往只有不同的途径,主要可以分为三种:反射型XSS存储型XSS基于DOM的XSS

  • 反射型XSS:用户的恶意代码字符串来源于受害者的请求,例如,邮件中参杂的恶意链接。
  • 存储型XSS:用户的恶意代码字符串来自于网站的数据库。通常是我们图中举的例子——在评论中注入恶意代码,让受害者进行访问
  • 基于DOM型XSS:这种攻击的漏洞主要在客户端,而非服务端。一般比较少见。

由于存储型的XSS的流程图,我们已经在上面看到过了。之后,我们需要来看一看反射型的XSS流程图,如图:

可以看到流程中,并未向网站的数据库中插入恶意代码,而是由以下4步骤组成:

  1. 攻击者向受害者传递一个网站URL地址
  2. 然后,受害者点击了这个地址,同时会向网站发出请求
  3. 网站响应原先已经存在恶意代码的网页给用户
  4. 当用户加载完网页之后,会向攻击者的服务器发送私密信息。

这种形式往往是需要用户进行点击的。

还有一种基于DOM的XSS,平时运用较少,而且攻击条件较为苛刻。在此不做讨论。

我们看完分类之后,对于攻击的大体流程已经掌握。

接下来的操作平台,我比较推荐——DVWA。因为目前网上XSS漏洞比较少,主要也是因为开发者的重视,而且网上操作会导致一定的危害,所以在本地搭建开发环境是最好的选择。

实际操作:

最初,我们需要安装DVWA,这个教程网上有很多,所以,可以自行百度。

第一步,我们需要将DVWA的安全级别调低,因为不同的安全级别采取的防御措施不同。

第二步,我们开始在XSS reflected中进行xss试验。

第三步,在输入框中输入"<script>alert(document.cookie)</script>",如图:

第四步:提交之后,我们即可看到弹窗(这里提醒一下尽量不要使用chrome,那个浏览器会屏蔽这些,最好使用老版本的IE),如图:

如果你具备后台服务器的话,那么就可以将这个cookie通过请求的形式发送到服务器后台上面,此处就不做演示了。

防御

既然有人企图使用这些玩意来危害使用者,那么,我们这些开发者在开发应用的过程中,自然会有应对之策。不知你还记得上面的攻击流程图没有?如果忘记了,不妨回去看一眼。因为,最好的防御措施就是截断攻击环节中的任意一个环节。

首先,作为一个开发者,必须达成的一点共识是所有的用户输入都是不安全的。尤其是类似于XSS这类的注入型漏洞。我们可以通过两个方式对其进行防御——编码验证

编码:对于用户的输入而言,所输入的内容只会作为数据,而不是代码。

验证:通过正则表达式等方式,去检查用户的输入中是否带有敏感字符等。

所以,我们的解决方案可以围绕上述两点进行展开:

  1. 输入检测
    对用户输入的数据进行检测。对于这些代码注入类的漏洞原则上是不相信用户输入的数据的。所以,我们要对用户输入的数据进行一定程度上的过滤,将输入数据中的特殊字符与关键词都过滤掉,并且对输入的长度进行一定的限制。只要开发的人员严格检查每个输入点,对每个输入点的数据进行检测和xss过滤,是可以阻止xss攻击的。
  2. 输出编码
    通过前面xss的原理分析,我们知道造成xss的还有一个原因是应用程序直接将用户输入的数据嵌入HTML页面中了。如果我们对用户输入的数据进行编码,之后在嵌入页面中,那么html页面会将输入的数据当作是普通的数据进行处理。
  3. Cookie安全
    利用xss攻击,我们可以轻易的获取到用户的cookie信息。那么我们需要对用户的cookie进行一定的处理。首先,我们尽可能减少cookie中敏感信息的存储,并且尽量对cookie使用hash算法多次散列存放。合理的使用cookie的httponly的属性值。这样可以防止恶意的js代码对cookie的调用。
  4. 禁用脚本
    可以在浏览器中进行js的安全设置。类似与chrome等浏览器都会拦截一些危险的xss操作,例如:想要读取cookie时,浏览器会阻止这个操作,征求用户指示,同时提醒用户此类操作的危害性。

对于XSS而言,我们可以了解的内容就到此为止。如果你想要深究,可以看一些网络安全的书籍,或者查阅其他的文章,均可得到详细的解答。下面我们需要介绍我们的第二位主角——CSRF

第二位主角——CSRF

还记得第一位主角的名字叫什么吗?是叫——跨站脚本攻击。那么第二位主角也有一个类似的名字——跨站请求伪造(Cross-site request forgery)。

概述

CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。

CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到06年才开始被关注,08年,国内外的多个大型社区和交互网站分别爆出CSRF漏洞,如:NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站),YouTube和百度HI......

或许,我们现在对它了解的少了,但是网络中的确还留有它的足迹。我们具体的操作就不实际操作了。我们可以来看一下CSRF的原理,如图(该图来自一篇知名的博客,在此注明):

可以从图中看到以下步骤:

  1. 首先用户会登录网站A,之后在通过验证之后,会由cookie来进行信息的传递
  2. 这时,用户又访问了网站B(例如:邮件链接等形式),用户会在不知情的情况下,利用用户在网站A的cookie,对网站A发送第三方请求。
  3. A站点通常不会关注这个访问是来自用户或者网站B

分类

CSRF也可会分成两种形式的攻击:站内攻击站外攻击

CSRF站内类型的漏洞在一定程度上是由于程序员滥用$_REQUEST类变量造成的,一些敏感的操作本来是要求用户从表单提交发起POST请求传参给程序,但是由于使用了$_REQUEST等变量,程序也接收GET请求传参,这样就给攻击者使用CSRF攻击创造了条件,一般攻击者只要把预测好的请求参数放在站内一个贴子或者留言的图片链接里,受害者浏览了这样的页面就会被强迫发起请求。

CSRF站外类型的漏洞其实就是传统意义上的外部提交数据问题,一般程序员会考虑给一些留言评论等的表单加上水印以防止SPAM问题,但是为了用户的体验性,一些操作可能没有做任何限制,所以攻击者可以先预测好请求的参数,在站外的Web页面里编写javascript脚本伪造文件请求或和自动提交的表单来实现GET、POST请求,用户在会话状态下点击链接访问站外的Web页面,客户端就被强迫发起请求。

防护

CSRF,对于目前而言攻击较少,也是因为对于这方面的防御手段越来越成熟所导致的。下面,我们来看一下如何去防护CSRF的攻击。

预防CSRF攻击可以从两方面入手:

  • 正确使用GET、POST和cookie
  • 在非GET请求的时候添加伪随机码

何为正确使用GET和POST呢?拿RESTful API举例来说,GET是获取资源,而POST是提交修改资源。那么我们在定义一个url时,遵循这个规则,就可以保证GET的非用户请求,无法对服务器资源进行修改,这样就可以防止GET的CSRF攻击。

那么,你可能会疑惑,要是POST的请求攻击怎么办呢?这就需要从第二方面下手。

增加伪随机码的方式,一般可以分为三种:

  • 为每个用户生成一个cookie token,这样可以保证在每次表单验证时附带上同一个伪随机码。这种方式是最简单的,但是同时也需要保证cookie的安全。往往cookie中的信息是非常容易被盗取的,所以这种方案在保证没有XSS的前提下是比较安全的。
  • 每次请求生成验证码。这种方法是安全的,但是相对于用户体验来说,并不友好
  • 不同表单包含一个不同的token。有兴趣可以去了解一下,这种是比较安全的POST请求方式。

小结

由于,现在对于CSRF的攻击预防比较彻底,一般在没有XSS的前提下,已经很难进行此类攻击了。所以真实的实际操作环境并没有多少。以往主要的攻击手段还是,通过XSS对于cookie进行盗取,然后通过CSRF用户数据进行修改。我们可以一个例子来说明最经典的银行的例子:

如果银行A允许以GET请求的形式来转账,我们这里大多指的不是实际生活中的,因为实际生活中银行不可能只用get请求转账这么简单操作:http://www.mybank.com/Transfe...

这是危险网站B的代码段中有这么一句:

<img src=” http://www.mybank.com/Transfer.php?toBankId=11&money=1000”>

那么当你再回A银行时,就会发现你的账户上已经少了1000元。

当然,这是假的。

总结

前端安全,一直以来都是被关注的重点对象。我们在了解他们的同时,应该注重他们的防护,这就是对用户的包含。可以是XSS的漏洞,时有发生,BAT等大厂的产品也不例外。今天总结了XSS和CSRF的攻击与防护,是警醒自己,在以后的开发中多加注意,同时,也希望和你们一起分享。

如果你对我写的有疑问,可以评论,如我写的有错误,欢迎指正。你喜欢我的博客,请给我关注Star~呦github博客

你可能感兴趣的文章

载入中...
zimo zimo

1.1k 声望

发布于专栏

前端随笔

或许,我们之间只是一篇文章的距离;知识,只是几分钟的阅读。希望我们能够在此专栏里面一起成长,一起进步。 no regrets yesterday, more struggling today, looking forward to tomorrow

22 人关注