前言
一直不怎么关注浏览器安全,最近上课时无聊,又重新看了《白帽子讲Web安全》第二篇 客户端脚本安全,虽然书是老的但是很经典,发现了许多之前没有注意的点
同源策略
同源策略(同源是指”协议+域名+端口“三者相同)是一种约定,它是浏览器最核心也最基本的安全功能,Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现
同源策略限制内容有:
Cookie、LocalStorage、IndexedDB
等存储性内容
DOM 节点
AJAX 请求(XMLHttpRequest)
发送
浏览器中,<script>、<img>、<iframe>、<link>等标签
都可以跨域加载资源,而不受同源策略的限制。这些带“src”属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容(如结合合适的 CORS 响应标头,才可以实现在 <canvas>
中使用外部域加载的 <img>
元素)。并且Safari 和 Firefox等浏览器禁止在<img>、<iframe>、<script>、<link>等标签
中发送不属于当前访问网站域名的第三方 Cookie。
跨域解决方案
如果想要使用另外一个域名的资源但是不想从后端出发
五种绕过同源策略的方法
JSONP 请求本质上是利用了 “Ajax 请求会受到同源策略限制,而 script 标签请求不会” 这一点来绕过同源策略
CORS机制 它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源
Nginx 代理转发 设置路由,访问路由时,反向代理拿到客户端的请求,将请求转发给其他的服务器
websocket通讯 WebSocket可以双向通讯,并且没有同源限制,客户端可以与任意服务器通信。
postMessage 通常用于嵌入的页面获取主页面的数据
其中两种绕过同源策略的方法可能会引起csrf
JSONP
前面提到了<script>
可以跨域加载资源,但是不能对返回的内容进行修改,所以让后端’主动’调用前端js
JSONP是服务器与客户端跨源通信的常用方法,JSON with Padding,填充式JSON或者说是参数式JSON
JSONP原理就是后端得到数据后,通过主动调用js函数并填入自定义参数,从而解决不同源js不能读返回的内容的限制
jsonp漏洞侧重点是数据,csrf影响的是操作
实例
1 | <!DOCTYPE html> |
如果JSON数据涉及一些敏感数据,就可以造成信息泄露或者在js函数中劫持做一些危险操作,所以与下面的cors相比利用面比较小
CORS
前面不是说了吗,同源策略限制了AJAX 请求,这也在开发中造成了许多不便,所以引进了cors机制
CORS是跨域资源共享(Cross-Origin Resource Sharing)的缩写,它允许浏览器向跨源服务器,发出XMLHttpRequest请求
如xhr.open('GET', 'https://api.example.com/data', true);
,如果第二个参数是一个不同的域名,请求包就会自动加上Origin 字段表明请求来自域名,该字段不允许js脚本修改,服务端会返回Access-Control-Allow-Origin
表明可以接受跨域的域名,浏览器会进行比较如果不对应的话,就会报错阻止后续访问
实例
1 |
|
CSRF的防御
- 验证码
- Referer Check
Referer字段也不允许js修改,绕过方法总体来说有2种
第一种就是空referer
第二种就是和任意URL跳转一样的绕法 - Token
Token需要同时放在表单和Session中。在提交请求时,服务器只需验证表单中的Token,与用户Session(或Cookie)中的Token是否一致,如果一致,则认为是合法请求;如果不一致,或者有一个为空,则认为请求不合法,可能发生了CSRF攻击。应该尽量把Token放在表单中。把敏感操作由GET改为POST,以form表单(或者AJAX)的形式提交,可以避免Token泄露。 - 设置SameSite
通过设置Cookie的 SameSite 属性来限制网站cookie的传递。当设置为 strict 模式时,cookie只能在第一方网页中发送使用,而不会发送给第三方网站post csrf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://baidu.com/adminPage/admin/addOver">
<input type="hidden" name="id" value="" />
<input type="hidden" name="name" value="test" />
<input type="hidden" name="api" value="false" />
<input type="hidden" name="type" value="0" />
<input type="hidden" name="parentId" value="" />
<input type="hidden" name="pass" value="e10adc3949ba59abbe56e057f20f883ec7231c2ecd7fa89fd6bae6e81d2adc80" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>post json下的csrf的利用
- 修改Content-Type字段
未校验Content-Type字段,为text/plain
依旧可以访问
修改Content-Type为application/x-www-form-urlencoded
,若可以访问,则说明服务端除了可以识别json以外还可以使用表单数据传输参数 - XHR发送请求
通过XHR提交Content-Type肯定没问题,但是当跨域请求为复杂请求时,浏览器会发送OPTIONS请求,然而如果服务端对Content-Type进行校验,则不会响应这个OPTIONS请求1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<html>
<body>
<script>
function submitRequest()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.xxxxx.com/simauth/app/updateAppInfo", true);
xhr.setRequestHeader("Accept", "*/*");
xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.withCredentials = true;
xhr.send(JSON.stringify({"appId":"300016001555","appName":"0xdawn"});
}
</script>
<form action="#">
<input type="button" value="Submit request" onclick="submitRequest();"/>
</form>
</body>
</html> - Flash + HTTP 307
Flash可以自定义Header请求,从而伪造Content-Type字段https://github.com/appsecco/json-flash-csrf-poc
csrf的利用场景
OAuth缺陷导致任意账号接管
点击劫持
iframe页面
iframe页面是一种在html文档中嵌入其他html文档的技术,如果页面允许被别的页面加载,攻击者使用一个透明的,不可见的iframe,覆盖在一个网页上,然后诱导使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面上的链接
漏洞防御
主要有三种防御办法:
1)X-Frame-Options,建议设置为DENY;
DENY:浏览器会拒绝当前页面加载任何frame页面
SAMEORIGIN:则frame页面地址只能为同源域名下的页面
ALLOW-FROM origin:则可以定义允许frame加载的页面地址
2)Content-Security-Policy(csp):frame-ancestors ‘self’或‘none’,不适用于Safari和IE;
3)js层面:使用iframe的sandbox属性,判断当前页面是否被其他页面嵌套。
1 |
|