同源策略:
所谓同源策略,它是浏览器的一种最核心最基本的安全策略。它对来至不同源的文档或这脚本对当前文档的读写操作做了限制。
同协议、ip、端口的脚本才会执行。
只要协议、域名、端口有任何一个不同,都被当作是不同的域.
js跨域是指通过js在不同的域之间进行数据传输或通信.
-
-
- 为什么限制跨域
-
为什么要有这个策略,想必你已经知道,那就是因为保证用户的信息安全。
假如没有同源策略
- 假设现在有a.com和b.com两个域,如果没有这一安全策略,那么当用户在访问a.com时,a.com的一段脚本就可以在不加载b.com的页面而随意修改或者获取b.com上面的内容。这样将会导致b.com页面的页面发生混乱,甚至信息被获取,包括服务器端发来的session。这样的话,我们的web世界将是一片混乱。也是因为浏览器的同源策略,保证来至不同源的对象不会互相干扰,保证了我们访问页面最基本的安全。
- 比如,cookie一般用于状态控制,常用于存储登录的信息,如果允许跨域访问,那么别的网站只需要一段脚本就可以获取你的cookie,从而冒充你的身份去登录网站,造成非常大的安全问题,因此,现代浏览器均推行同源策略。
-
- 什么会限制跨域
-
限制跨域
- cookie
- localStorage
- ajax请求
src可以跨域
在这里需要注意的是,文档中的所有带“src”属性的标签都可以跨域加载资源,而不受同源策略的限制。
如<script>、<img>、<iframe>、<link>等。如果你在页面定义了这些标签,在页面加载时都对不同源的资源发起了一次GET请求。但是通过src加载的资源,浏览器限制了脚本对其返回的内容无法读写。特别是在ajax请求的时候,特别要注意XMLHttpRequest的时候是无法跨域访问的。
-
-
- 怎么解决跨域
- 通过修改document.domain来跨子域
- 怎么解决跨域
-
同源策略认为域和子域属于不同的域,如:
child1.a.com 与 a.com,
child1.a.com 与 child2.a.com,
xxx.child1.a.com 与 child1.a.com
两两不同源,可以通过设置 document.damain='a.com',浏览器就会认为它们都是同一个源。想要实现以上任意两个页面之间的通信,两个页面必须都设置documen.damain='a.com'。
此方式的特点:
1. 只能在父域名与子域名之间使用,且将 xxx.child1.a.com域名设置为a.com后,不能再设置成child1.a.com。
2. 存在安全性问题,当一个站点被攻击后,另一个站点会引起安全漏洞。
3. 这种方法只适用于 Cookie 和 iframe 窗口。
-
-
-
- 使用window.name来进行跨域
-
-
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
// 打开必应 https://www.bing.com/
// 保留控制台log(勾上Preserve log
> window.name
""
> window.name='text';
"text"
> location.href='http://www.google.com';
"http://www.google.com"
Navigated to https://www.google.com/
> window.name
"text
我们知道,使用iframe的src属性,可以加载不同域中的网页,
我们也可以使用$('iframe').contentWindow来拿到iframe中页面的window对象,
只是这个window对象中可以访问的属性是很少的。
window.name这个属性不是一个简单的全局属性 ---
只要在一个window下,无论url怎么变化,只要设置好了window.name,那么后续就一直都不会改变,同理,在iframe中,即使url在变化,iframe中的window.name也是一个固定的值,利用这个,我们就可以实现跨域了。
下面是localhost:8088/test2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test2</title>
</head>
<body>
<h2>test2页面</h2>
<script>
var person = {
name: 'wayne zhu',
age: 22,
school: 'xjtu'
}
window.name = JSON.stringify(person)
</script>
</body>
</html>
即我们希望吧test2.html中的数据传递出去,到localhost:8081/test1.html中去。
下面是localhost:8081/test1.html
这里的意图很明确,就是使用iframe将test2.html加载过来,因为只是为了实现跨域,所以将之隐藏,但是,这时已经完成了最重要的一步,就是将iframe中window.name已经成功设置,但是现在还获取不了,因为是跨域的,所以,我们可以把src设置为当前域的proxy.html。
另外,这里之所以要设置flag,是因为每当改变location的时候,就会重新来一次onload,所以我们希望获取到数据之后,就直接close(),故采用此种方法。
这个proxy.html内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>proxy</title>
</head>
<body>
<p>这是proxy页面</p>
</body>
</html>
是的,什么都没有,当然,我们也可以把src就替换成test1.html,但是这样的坏处很明显,就是需要把test1.html中的数据加载一遍,这不是我们所希望的。
-
-
-
- 使用HTML5新提供的postMessage api
-
-
/* 子窗口 */
window.onmessage = function(e) {
if (e.origin !== 'http://bbb.com') return;
var payload = JSON.parse(e.data);
switch (payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, 'http://aaa.com');
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
};
/* 父窗口 */
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
// 存入对象
win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
// 读取对象
win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
window.onmessage = function(e) {
if (e.origin != 'http://aaa.com') return;
// "Jack"
console.log(JSON.parse(e.data).name);
};
-
-
-
- 1. 通过jsonp跨域
-
-
jsonp在页面上引入不同域上的js脚本文件实现请求不同域上的数据
(1) 通过script标签引入一个js文件
(2) js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入
注:需要服务器端的页面进行相应的配合。
JSONP的原理:(举例:a.com/jsonp.html想得到b.com/main.js中的数据)在a.com的jsonp.html里创建一个回调函数xxx,动态添加<script>元素,向服务器发送请求,请求地址后面加上查询字符串,通过callback参数指定回调函数的名字。请求地址为http://b.com/main.js?callback=xxx。在main.js中调用这个回调函数xxx,并且以JSON数据形式作为参数传递,完成回调。
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
//window.onload是为了让页面加载完成后再执行
function foo(data) {
console.log(data.name+"欢迎您");
};
//b.com/main.js中的代码
foo({name:"hl"})
这样便实现了跨域的参数传递。
采用jsonp跨域也存在问题:
1. 使用这种方法,只要是个网站都可以拿到b.com里的数据,存在安全性问题。需要网站双方商议基础token的身份验证,这里不详述。
2. 只能是GET,不能POST。
3. 可能被注入恶意代码,篡改页面内容,可以采用字符串过滤来规避此问题。
客户端页面完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> <title>JSONP 实例</title>
</head>
<body>
<div id="divCustomers"></div>
<script type="text/javascript">
function callbackFunction(result, methodName) {
var html = '<ul>';
for(var i = 0; i < result.length; i++) {
html += '<li>' + result[i] + '</li>';
}
html += '</ul>';
document.getElementById('divCustomers').innerHTML = html; }
</script>
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction">
</script>
</body>
</html>
-
-
-
- WebSocket
-
-
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
-
-
-
- CORS
-
-
CORS全称cross-origin resource sharing,意为跨站点资源共享,是w3c官方推荐的一种跨域方案,目前所有浏览器对其兼容性都表现良好,而且支持所有的请求方式,可以预见是未来最为广泛使用的跨域方案。
在支持CORS方案的浏览器中发送AJAX请求,请求地址为目标域的绝对路径时,请求头中会带有一个字段:withCredentials: true,这个字段会让浏览器发送身份信息到服务端,如SSL、cookie等。与此同时,在服务端中设置响应头中的Access-Control-Allow-Origin: *,则可以实现一个跨域请求。
注意:在实际使用中,最好对Access-Control-Allow-Origin进行指定域名的设置,如:Access-Control-Allow-Origin: www.test.com。如果使用Access-Control-Allow-Origin: *,则会允许所有来源进行跨域访问,这会带来比较大的安全问题。
-
-
-
- 服务器代理
-
-
Nginx proxy_pass
# 80 cat
upstream pig-client {
server 127.0.0.1:80 fail_timeout=0;
}
# app
upstream pig-control {
server 127.0.0.1:8080 fail_timeout=0;
}
#page 新阳蓝光项目
upstream pig-xinyang {
server 127.0.0.1:4200 fail_timeout=0;
}
server {
listen 80;
server_name hardboy.cn;
index index.html index.htm;
location / {
proxy_pass http://pig-client;
try_files $uri $uri/ /index.html =404;
}
}
server {
listen 80;
server_name notapig.cn;
index index.html index.htm;
location / {
proxy_pass http://pig-xinyang;
try_files $uri $uri/ /index.html =404;
}
}