You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

13 KiB

21XSS前端攻防的主战场

你好,我是王昊天。

如今我们开发一个Web应用需要用到前端和后端两部分。其中前端主要用于数据的渲染将信息更好地展示给我们后端则需要获取数据将合适的信息展示给我们。只有前端和后端一起合作才能构建出一个优秀的Web应用。

在之前的课程中我们学习了SQL注入、命令注入这两种注入攻击它们都是针对Web后端的攻击。那么注入攻击可以针对前端执行吗答案是肯定的今天我们要学习的XSS即跨站脚本攻击就是针对前端的攻击方式下面让我们开始对它的学习吧。

XSS介绍

XSS即跨站脚本攻击是OWASP TOP10之一。它的全称为Cross-site scripting之所以缩写为XSS是因为CSS这个简称已经被占用了。这就是XSS名称的由来。

XSS攻击的原理为浏览器将用户输入的恶意内容当做脚本去执行,从而导致了恶意功能的执行,这种针对用户浏览器的攻击即跨站脚本攻击。它的攻击方式可以分为三种类型,我在下图将它们列举出来了。

图片

下面让我们进一步来学习它的攻击方式吧。

反射型XSS

当应用程序将收到的用户输入直接作为HTML输出的一部分时并且未经验证或转义攻击者就可以输入一些JavaScript脚本使得受害者的浏览器执行任意的JavaScript代码。这就是反射型XSS攻击之所以称之为反射型XSS是因为这种攻击需要用户提供一个恶意输入然后页面据此进行反射执行攻击的命令。

为了加深你的理解,我们一起来看一个示例。

图片

上述是一个反射型XSS注入的靶场我们需要在其中输入并上传两个参数First name以及Last name然后该Web应用在接收到上传的参数后会将它们显示在页面上如Welcome firstname lastname。

查看页面的元素我们可以看到输入的参数直接被放在HTML的body中。

<body>
  # ...
  <div id="main">
  # ...
  "Welcome first name last name"
  </div>

由于页面中没有对我们的输入进行限制导致了我们可以直接在First name中输入在Last name中随意输入任何字符串例如abc这样就能导致XSS攻击。

图片

可以看到我们输入的恶意JavaScript脚本alert(1)已经执行成功,弹出了一个警告框。我们再次检查页面的源代码,发现如下所示:

<body>
  # ...
  <div id="main">
  # ...
  " Welcome “
  <script>alert(1)</script>
  ” abc "
  </div>

我们在First name中输入的恶意脚本被解析为JavaScript命令所以我们的攻击成功了。

上面例子中的行为看似是我们自己在攻击自己但事实上也可以攻击别人使得别人在访问一个页面时受到我们发起的XSS攻击。你可以想一想要如何利用反射型XSS攻击别人

事实上我们发送的First name以及Last name都是通过GET方式上传的参数而在之前的学习中我们知道以GET方式上传的参数会出现在链接中例如我们将First name设为将Last name设为abc那么对应的恶意链接就如下所示

http://1e2b92939584409b89297897efdf1599.app.mituan.zone/xss_get.php?firstname=%3Cscript%3Ealert%281%29%3C%2Fscript%3E&lastname=abc&form=submit

我们只需要将这个恶意链接发送给要攻击的目标即可,这样只要受害者点击链接,那么恶意命令就会在受害者的浏览器执行。

上述示例中Web没有对我们的输入做任何限制使得我们的JavaScript脚本顺利执行接下来我们来看反射型注入如果受到限制该如何破解呢

图片

例如这个示例中我们输入一个JavaScript脚本但是它就不会被执行通过查看页面源代码

<p>Hello <script>alert(1)</script>, please vote for your favorite movie.</p>

我们可知,它不会被执行的原因是

将我们的输入包裹起来了在HTML中这代表了限制其中包裹的内容为文本那么这里你有什么好办法来绕过这个限制吗

**比如类似SQL注入中的闭合操作**没错,我们可以将它的

标签闭合起来,构造输入如下:

# 输入为:
</p><script>alert(1)</script><p>
# 响应的html变为
<p>Hello </p><script>alert(1)</script><p>, please vote for your favorite movie.</p>

这样我们就可以将

标签闭合成功执行我们的JavaScript恶意代码。

从上述内容中我们可以知道反射型XSS具有非持久化的特点因为用户必须点击带有恶意参数的链接才能引起这个攻击。同时它的影响范围很小只有那些点击了恶意链接的用户才会受到它的攻击。

接下来让我们进入到另一种更危险的XSS攻击中——存储型XSS攻击。

存储型XSS

存储型XSS是指应用程序通过Web请求获取不可信赖的数据在未检验数据是否存在XSS代码的情况下便将其存入数据库。当下一次从数据库中获取该数据时程序也没有对其进行过滤使得页面再次执行XSS代码。与反射型XSS不同的是存储型XSS可以持续攻击用户。

攻击者想要发起存储型XSS攻击首先需要将恶意代码进行上传上传的位置主要有留言板、评论区、用户头像、个性签名以及博客。如果Web应用没有限制上传的内容并且将该内容存储到了数据库中那么存储型XSS就成功了第一步。

接下来想要使得存储型XSS攻击生效还需要让Web应用去读取之前存储的恶意代码。这其实很简单我们可以想一想留言板我们只要上传一条留言那么每次去访问这个留言板时系统就会自动去读取之前上传的所有数据并在页面上显示出来。当然系统可能会对读取的数据做一定的限制如果我们的恶意代码没有被限制那么我们的存储型XSS攻击的第二步也就成功了。

完成了读取后,系统会将内容进行解析读取,如果解析的时候没有成功限制住我们的恶意代码,那么我们之前存储的恶意命令将被执行。存储型XSS攻击也就成功啦

下面让我们一起看一个示例来加深一下对存储型XSS攻击的理解。

图片

在这个示例中Web应用选择的为一个博客我们可以在此输入一个恶意命令作为博客并且进行上传。例如我们输入点击上传之后页面会刷新并且弹出警告框1之后这个页面每次被访问都会引起恶意命令的执行。

从结果我们知道我们的恶意命令成功执行这代表了我们的恶意输入被上传到数据库中并且Web应用读取了它将它解析出来。

根据我们对存储型XSS攻击的了解我们不难知道它的危害性是远远高于反射型XSS攻击的。因为它的影响范围远远高于反射型XSS它会影响到所有访问到受攻击Web页面的用户。

完成了存储型XSS攻击的学习后接下来让我们接着学习DOM型XSS攻击。

DOM型XSS

首先我们需要知道什么是DOMDOM就是文档对象模型它可以将文档解析成一个由节点和对象包含属性和方法的对象组成的结构集合。简单来讲它会将Web页面和脚本程序连接起来。

DOM型XSS攻击其实是一种特殊类型的反射型XSS通过JavaScript操作DOM树动态地输出数据到页面而不依赖于将数据提交给服务器端它是基于DOM文档对象模型的一种漏洞。

根据之前的学习我们可以明白在DOM型XSS中整个过程和后端无关它完全是基于前端的攻击所以当我们遇到要绕Waf的时候就可以使用这种攻击因为Waf是基于后端进行拦截的。

DOM型XSS的攻击方式其实与反射型XSS很相似它们都是没有控制好输入并且把JavaScript脚本作为输出插入到HTML页面。不同的是反射型XSS经过后端语言处理后页面引用后端输出生效。**而DOM型XSS是经过JavaScript对DOM树直接操作后插入到页面。**相比于反射型XSS攻击它的危害性更大因为它不经过后端所以可以绕过Waf的检测。

下面让我们从实战中更深入地学习DOM型XSS攻击。

实战演练

在这个案例中该靶场已经搭建于谜团中你可以访问DVWA靶场进行实战测试。

我们在登录后选择DVWA Security为low然后打开XSS(DOM)靶场。

图片

打开后发现了一个选择框我们无法从这里进行输入通过点击Select按钮我们从链接中可以发现它是通过GET方式上传的参数。

http://51277f5dd0db4fd0a6272f5f647b27b8.app.mituan.zone/vulnerabilities/xss_d/?default=English

这就给了我们输入的机会,然后进一步观察页面的源代码,对此进行分析。

if (document.location.href.indexOf(“default=“) >= 0) {
                        var lang = document.location.href.substring(document.location.href.indexOf(“default=“)+8);
                        document.write(“<option value=‘” + lang + “’>” + decodeURI(lang) + “</option>”);
                        document.write(“<option value= disabled=disabled>——</option>”);
                    }

从源代码中我们可知这个页面属于DOM型XSS攻击它没有经过后端处理是直接用document.write函数将输入显示在页面中并且没有做任何限制。因此我们可以用下述链接执行我们的攻击命令

http://51277f5dd0db4fd0a6272f5f647b27b8.app.mituan.zone/vulnerabilities/xss_d/?default=<script>alert(1)</script>

图片

可以看到,我们的攻击已经成功,一个警告框已经弹出来了。

总结

在这节课里我们首先了解了什么是XSS攻击并且知道它主要可以分为三种不同的类型包括反射型XSS、存储型XSS以及DOM型XSS。之后我们对它们分别展开了具体的学习。

在对反射型XSS的学习中我们知道反射型XSS的攻击需要用户提供一个恶意输入然后页面据此进行反射执行攻击的命令。同时我们也知道了当我们的输入被HTML标签限制住可以用闭合的方法来解除它的限制。反射型XSS具有非持久化的特点因为用户必须点击带有恶意参数的链接才能引起这个攻击同时它的影响范围很小只有那些点击了恶意链接的用户才会受到它的攻击。

之后我们学习了危害性更大的存储型XSS存储型XSS是指应用程序通过Web请求获取不可信赖的数据在未检验数据是否存在XSS代码的情况下便将其存入数据库。当下一次从数据库中获取该数据时程序也没有对其进行过滤使得页面再次执行XSS代码。与反射型XSS不同的是存储型XSS可以持续攻击用户我们每次访问被攻击的Web页面都会受到这个攻击的影响。

最后我们学习了DOM型XSS攻击经过学习我们知道DOM型XSS攻击其实是一种特殊类型的反射型XSS通过JavaScript操作DOM树动态地输出数据到页面而不依赖于将数据提交给服务器端它是基于DOM文档对象模型的一种漏洞。它与反射型XSS不同的是反射型XSS经过后端语言处理后页面引用后端输出生效。而DOM型XSS是经过JavaScript对DOM树直接操作后插入到页面。相比于反射型XSS攻击它的危害性更大因为它不经过后端所以可以绕过Waf的检测。

思考

最后留给你一道思考题XSS攻击有什么防范方法吗

欢迎在评论区留下你的思考。如果觉得今天的内容对你有所帮助的话,也欢迎你把课程分享给其他同事或朋友,我们共同学习进步!