一、同源和非同源
含义:
协议相同、域名相同、端口相同
目的:
保证用户安全信息,防止恶意网站窃取数据
二、利用document.domain降域实现跨域
原理:
利用的是document.domain降域来实现cookie获取的限制
新建两个文件夹分别为cookie_origin和cookie_orign_sub,以及建立了两个网站(master.security.com和slave.security.com页面)
配置虚拟主机(小皮)
打开D:\phpstudy_pro\Extensions\Apache2.4.39\conf\vhosts选择default-default.conf编辑以下内容
<VirtualHost *:80>
DocumentRoot "D:/phpstudy_pro/WWW/cookie_origin"
ServerName master.security.com
FcgidInitialEnv PHPRC "D:/phpstudy_pro/Extensions/php/php5.6.9nts"
AddHandler fcgid-script .php
FcgidWrapper "D:/phpstudy_pro/Extensions/php/php5.6.9nts/php-cgi.exe" .php
<Directory "D:/phpstudy_pro/WWW/cookie_origin">
Options FollowSymLinks ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
DirectoryIndex index.php index.html
</Directory>
</VirtualHost>
<VirtualHost *:80>
DocumentRoot "D:/phpstudy_pro/WWW/cookie_origin_sub"
ServerName slave.security.com
FcgidInitialEnv PHPRC "D:/phpstudy_pro/Extensions/php/php5.6.9nts"
AddHandler fcgid-script .php
FcgidWrapper "D:/phpstudy_pro/Extensions/php/php5.6.9nts/php-cgi.exe" .php
<Directory "D:/phpstudy_pro/WWW/cookie_origin_sub">
Options FollowSymLinks ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
DirectoryIndex index.php index.html
</Directory>
</VirtualHost>
![](https://img-blog.csdnimg.cn/img_convert/68bc5dbcb6e6c8e3360ce42ebd22f8cd.png)
打开D:\phpstudy_pro\Extensions\Apache2.4.39\conf的httpd.conf文件,去掉如下注释
LoadModule vhost_alias_module modules/mod_vhost_alias.so
![](https://img-blog.csdnimg.cn/img_convert/27db1499e8683d4008314643cb80bc07.png)
打开C:\Windows\System32\drivers\etc的host文件,编辑一下内容
127.0.0.1 master.security.com //主页面
127.0.0.1 slave.security.com //子页面
![](https://img-blog.csdnimg.cn/img_convert/58925dab0ab64d1578e79103f5a04396.png)
在建立的cookie_origin文件下新建一个html网页
访问网站是否成功
![](https://img-blog.csdnimg.cn/img_convert/c3ed663fb1f323ee32a5fe0e97c15e24.png)
在cookie_origin文件下写入以下内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>master</title>
</head>
<body>
<h1>master</h1>
<iframe src="http://slave.security.com" id="iFrame"></iframe>
</body>
<script>
document.domain = 'security.com';
let ifr = document.getElementById('iFrame');
ifr.onload = function() {
let win = ifr.contentWindow;
alert(win.data)
}
</script>
</html>
该代码的意思是利用iframe标签来嵌套一个子页面slave.security.com定义的唯一固定id为iFrame,之后利用document.domain给他们降级到同一个域级,这样他们之间就可以实现网页之间的互相访问,设置一个onload函数用来监听,起作用是等iframe访问完成后进行监听子网页,之后利用contentwindow来抓取子页面的内容,最后利用window的data属性弹窗出我们的data数据。
在cookie_origin_sub下写入以下内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>slave</title>
</head>
<body>
<h1>slave</h1>
</body>
<script>
document.domain = 'security.com';
window.data = 'data:111';
</script>
</html>
最后检验我们的结果
![](https://img-blog.csdnimg.cn/img_convert/7c88fa43dad073cd44dc330f3a79dd5d.png)
三、利用location.hash配合iframe实现跨域(不推荐)
原理
#data就是location.hash,改变hash值不会导致页面刷新,所以可以利用hash值来进行数据的传递,所以我们利用ifrom这个标签来实现数据传输,子页面收到父页面的请求后修改父页面的hash值,但是由于两个页面不在同一个域下,所以浏览器不允许修改,需要子页面进行iframe请求父页面的同源页面c.html页面,之后将改变的hash值给我们的c.html,我们的c.html请求两次父页面就实现了跨域。
虚拟主机配置和上一个实验是一样的(主网页www.aaa.com子网页www.bbb.com)
在cross_origin编写以下内容
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>aaaaaaaaaa</title>
</head>
<body>
<div>aaaaaaaaaaaaa</div>
</body>
<script>
var ifr = document.createElement('iframe');
ifr.src = 'http://www.bbb.com#data';
ifr.style.display = 'none';
document.body.appendChild(ifr);//请求跨域的操作
function checkHash() {
try {
let data = location.hash ? location.hash.substring(1) : ' ';
console.log('获得到的数据是:', data);
} catch (e) {
}
}
checkHash();
window.addEventListener('hashchange', function (e) {
console.log('获得的数据是:', location.hash.substring(1));
});
</script>
</html>
该代码的意思是15-16行表示的是一个跨域的一个请求操作,之后进行一个哈希函数的的监听作用(checkhash),如果哈希值发生改变则会通过js.substring(1)从改变的第一个值进行截取,之后打印出改变的值,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cccccccccccc</title>
</head>
<body>
</body>
<script>
parent.parent.location.hash = self.location.hash.substring(1)
</script>
</html>
在cross_origin_sub编写一下内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>bbbbb</title>
</head>
<body>
<div>bbbbbbbbbbbb</div>
</body>
<script>
switch (location.hash) {
case "#data":
callback();
break;
}
function callback() {
const data = "some number: 1111"
// parent.location.hash = data;
try {
parent.location.hash = data;
} catch (e) {
// ie, chrome 下的安全机制无法修改 parent.location.hash
// 所以要利用一个中间的代理 iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://www.aaa.com/c.html#' + data; // 该文件在请求域名的域下
document.body.appendChild(ifrproxy);
}
}
</script>
</html>
子页面的意思是当收到父页面的一个请求后,通过switch函数来判断是不是”#data“如果是就调用callback函数,我们利用parent.location.hash = data;把callback函数把父页面的哈希值变成了some number: 1111,之后父页面监听后,便将我们改变的值传递给父页面,之后父页面会打印出来,结果我们发现不行,原因是由于浏览器的安全机制我们无法修改父页面的哈希值,所以产生了我们的第三方代理页面(c.html)其要求是必须和父页面同源。我们的办法是增加一个catch函数,当我们的try函数判断受到了浏览器安全机制的限制时候我们进入到catch函数中,在这个函数中我们重新请求了一个iframe页面嵌套请求,请求我们的c.html,因为我们是在c.html里面进行请求的,相当于我们在父页面的子页面里面又嵌套了一个子页面,所以我们需要传输两次到我们的父页面。那么这个c.html相当于一个中转站,将我们的somenumber传两次传回到我们的父页面。
整体的过程
父页面aaa.com先进行请求子页面bbb.com,请求完成后,利用checkhash监听子页面的的哈希值有木有发生变化,子页面在接收到父页面的请求后判断是否有#data这个哈希值,入过有就会将其的data改为some number:1111,这时候返回给父页面,由于父页面有安全机制,就会显示不是同源,这时候返回给我们的子页面,之后子页面就会在去请求父页面同源下的一个c.html页面,我们利用c.html来将我们bbb.com页面修改的哈希值返回两次parent给我们的父页面,之后我们父页面识别是同源下的页面请求,并且监听到哈希值发生改变就打印出我们的内容
结果
![](https://img-blog.csdnimg.cn/img_convert/676a869ebcd87ec2b109c28ca0536d66.png)
缺点
(1)数据直接暴露在了url中
(2)数据容量和类型都有限
四、利用windows.name进行跨域
1.原理和location.hash一样,只是父页面指向子页面,子页面a又指向子页面b,利用的子页面a做的跳
转而已。
2.父页面的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>window_name</title>
</head>
<body>
<script>
let data = '';
const ifr = document.createElement('iframe');
ifr.src = "http://www.aaa.com";
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function () {
ifr.onload = function () {
data = ifr.contentWindow.name;
console.log('收到数据:', data);
}
ifr.src = "http://www.security.com/c.html";
}
</script>
</body>
</html>
我们可以在该页面下新建一个iframe,该iframe的src属性指向服务器地址(利用iframe标签的跨域能力),服务器文件b.html设置好window.name值。但是由于a.html页面和该页面iframe的src不同源的话,则无法操作iframe里的任何东西,所以就取不到iframe的name值,所以我们需要在b.html加载完之后重新换个src区指向一个同源的html文件,或者设置成about:blank都行,这时候我们只要在a.html相同的目录下件一个c.html空白即可。如果不重新指向src的话直接获取的window.name的话就会报错。
3. c.html
window.name = "hello";
五、postMessage跨域(重点推荐)
原理
www.security.com到www.aaa.com实现跨域操作,官方使用window.postmessage,其原理就是从源区域跨域的时候,通过postmessage的方法属性,对发送的页面进行监听,跨域的页面也进行postmessage属性的一个监听,从而来实现跨域的操作
在postmessage.html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>postMessage</title>
</head>
<body>
<iframe src="http://www.aaa.com"></iframe>
<script>
window.onload = function () {
let targetOrigin = 'http://www.aaa.com';
//想要操作当前iframe的时候,就像该ifranme中postMessage()一个东西。
window.frames[0].postMessage('我要给你发消息了!', targetOrigin);
//*表示任何域都可以监听。
}
//当我监听到message事件的时候,我就知道有人向我发送数据了,我获得了数据就可以做对应的事情。内部对消息做实现
window.addEventListener('message', function (e) {
console.log('security.com接收到的消息:', e.data);
});
</script>
</body>
</html>
首先security页面向aaa页面发送页面的请求,之后通过postmessage对该网页发送一些消息,于此同时我们也可以通过
在aaa.com页面创建一个页面用来监听来自security页面的消息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>postmessag</title>
</head>
<body>
<div>aaaaaaaaaa</div>
<script>
window.addEventListener('message', function (e) {
if (e.source != window.parent) {
return;
}
let data = e.data;
console.log('aaa.com接收到的消息:', data);
parent.postMessage('我已经接收到消息了!', e.origin);
})
</script>
</body>
</html>
该页面利用window.addeventlistener来监听来自sercurity的消息,主要靠的是监听message这个属性,如果不是来自security的消息就拒绝掉,如果是的话会通过event.data来获取这个消息的内容,并且告诉父元素其已经接收到该消息。
4.结果
![](https://img-blog.csdnimg.cn/img_convert/84ac02f610d914e5d88f444ce399039f.png)
六、postmessage的localstorage存储数据
原理:
通过postmessage方法进行对别的页面进行localstore的读写存储
在www.security.com页面建立一个对其他页面的存储请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>localstorage</title>
</head>
<body>
<iframe src="http://www.aaa.com"></iframe>
<script>
window.onload = function () {
let targetOrigin = 'http://www.aaa.com';
//想要操作当前iframe的时候,就像该ifranme中postMessage()一个东西。
// var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'oupeng','age': 10 };
window.frames[0].postMessage(JSON.stringify({ key: 'storage', data: obj }), targetOrigin);
//*表示任何域都可以监听。
}
//当我监听到message事件的时候,我就知道有人向我发送数据了,我获得了数据就可以做对应的事情。内部对消息做实现
window.addEventListener('message', function (e) {
console.log('security.com接收到的消息:', e.data);
});
</script>
</body>
</html>
通过iframe对www.aaa.com页面进行一个请求,之后对该窗口进行一个获取window的属性,建立一个obj的对象,在这个对象里加入我们需要存储的内容,之后通过json.stringify属性将这个数据转换为json对象,在通过postmessage方法将其传递到www.aaa.com页面
3.在ww.aaa.com页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>localstorage</title>
</head>
<body>
<script>
window.addEventListener('message',receiveMessage);
function receiveMessage(event) {
if (event.origin !== 'http://www.security.com') {
return;
}
var payload = JSON.parse(event.data);
localStorage.setItem(payload.key, JSON.stringify(payload.data));
};
</script>
</body>
</html>
在www.aaa.com页面,通过监听window.message的属性从而来获取到来自www.security.com传递过来的数据,将其转换为字符串,然后通过localstorage.setitem将获取的obj方法存储到localstorage中。
4.结果
![](https://img-blog.csdnimg.cn/img_convert/91c756b11e8956347a95531db5af4cf6.png)
七、JSONP(极力不推荐,淘汰)
原理
通过建立一个<script>的请求,其不受跨源的要求,建立一个网页的请求,在建立的网页请求网址后面添加一个callback=foo的参数,并且通过拼接字符拿到foo这个函数中的内容。
2.在www.security.com建立一个请求拼接json的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jsonp</title>
</head>
<body>
<script>
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://www.aaa.com/index.html?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
</script>
</body>
</html>
该代码的意思是建立一个函数进行<script>的标签请求,在请求的网址后面加入callback=foo这个参数,并且在后面拼接出得出服务器请求的json数据
3.在www.aaa.com中创建一个json数据库
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>aaaaaaaaaa</div>
<script>
function foo(data){
console.info(data);
}
var obj = {'ip': '8.8.8.8'};
foo(obj);
</script>
</body>
</html>
其是指建立一个foo的json数据库,里面存放着我们需要请求的数据内容。
4.结果
![](https://img-blog.csdnimg.cn/img_convert/9983e63c2779254df0f5492336e4c164.png)
八、WebSocket
原理
WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
在本地建立socket.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>nodesjs</title>
</head>
<body>
<script>
let socket = new WebSocket('ws://127.0.0.1:3000');
socket.onopen = function () {
socket.send('l love you');
}
socket.onmessage = function (e) {
console.log(e.data);
}
</script>
</body>
</html>
该意思是利用websocket先进行ws的对websocket库进行一个请求,在通过socket.send方法对该库发送一条消息,之后在通过socket.onmessage方法对其进行一个数据的监听,从而获取数据。
3.建立socket.js库的相关配置
let express = require('express');
let app = express();
let WebSocket = require('ws');
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws){
ws.on('message',function (data) {
console.log(data);
ws.send('i hate you')
});
})
该库的意思是建立一个连接ws的3000端口请求,收到该请求后利用message来获取得到的数据,之后传递给请求页面一个l hate you的消息。
先在本地下载websocket服务器,之后node socket.js,最后访问www.security.com页
结果
![](https://img-blog.csdnimg.cn/img_convert/3fc1940eed5d684d428dd9ef3500acc4.png)
九、CORS(待补充,自己太菜了,弄不出来)
CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨域的服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制。