前台跨域问题总结

作者 : 开心源码 本文共5996个字,预计阅读时间需要15分钟 发布时间: 2022-05-11 共84人阅读

前台跨域问题的原因是什么—同源政策

1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
最初,它的含义是指,A网页设置的 Cookie,B网页不可以打开,除非这两个网页”同源”。所谓”同源”指的是”三个相同”。协议相同、域名相同、端口相同。

举例来说
http://shaocx.com/index.html 这个网址协议是http://,域名是www.example.com,端口是80(默认端口能省略)。
它的同源情况如下。
http://shaocx.com/index2.html 同源
https://shaocx.com/index2.html 不同源(协议不同)
http://www.shaocx.com/index.html 不同源(域名不同)
http://shaocx.com:81/index.html 不同源(端口不同)

同源政策的目的

同源策略有助于保护用经过验证会话的网站。下面是一个假如没有同源政策会出现的例子。

假设使用户正在访问一个银行网站并且没有注销。而后使用户打开了一个有恶意JavaScript代码的网站,该网站向银行网站请求数据。因为使用户没有注销银行网站上的账号,恶意代码在银行网站上做任意事情。例如,它能获取使用户最近一次交易的列表,或者者创立一个新交易等。

这主要是由于浏览器会根据请求的域名,自动加上之前存储在该域名底下的cookie。

而无意间访问恶意网站的使用户,会期望他或者她访问的网站无法访问银行会话cookie。虽然JavaScript没有直接访问银行会话cookie,但它依然能通过银行网站的会话cookie向银行网站发送和接收请求。因为脚本基本上能和使用户做的一样,所以银行网站的CSRF保护也不会有效。

由此可见,”同源政策”是必须的,否则 Cookie 能共享,互联网就毫无安全可言了。

同源政策限制范围

1、 Cookie、LocalStorage 和 IndexDB 无法读取。
2、 DOM 无法取得。
3、 AJAX 请求不可以发送。
4、 window对象无法获取。

Cookie

Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才可以共享。但是,当两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。

1、前台自己存取cookie时
A网页是http://w1.shaocx.com/a.html
B网页是http://w2.shaocx.com/b.html
document.cookie = “try1=1;domain=shaocx.com”;
这样cookie被设在顶级域名 .shaocx.com 上,两个页面都能读取到。

2、后台增加cookie时
服务器也能在设置Cookie的时候,指定Cookie的所属域名为一级域名,比方.shaocx.com。
Set-Cookie: key=value; domain=.shaocx.com; path=/

这里有少量地方需要注意:
1、挂载在顶级域名上的是这种格式 .a.com ,前台在设置、书写的时候,前面的 . 是不需要书写的。但是在后台加上的时候,这个 . 又是必需的。
2、cookie在读取的时候,只可以读取到key和value。(path、host、expires不可以读取)
3、cookie在读取时,假如你在多个域名下都设置了,那么会出现多个cookie。
4、多个cookie时读取的值会根据你用的方法有所不同。(我这边的Cookies用了js-cookie.js)
document.cookie会读取到所有能读取到的cookie。而且是根据先后插入的顺序进行读取。
Cookies.get()会读取先插入的值(根据document.cookie的顺序)。
Cookies.getJSON()会优先读取后插入的值(转换成对象后值被覆盖)。

iframe

iframe窗口和window.open方法打开的窗口一样,假如不同源,它们与父窗口无法通信。

先来回顾一下iframe之间互相通信的方法。
父子iframe互相操作
子iframe获取父iframe,parent.window,top.window
父iframe获取子iframe,document.getElementById(“a”).contentWindow

跨域会存在以下问题
window对象无法读取具体的对象值,只可以读取系统默认方法。
window.location 能设置,但不可以读取。其它的 location 属性和方法被禁止访问;
document 不能设置,也不可以读取。
<iframe> 的 src 能设置,也能读取。但是在iframe中将自己的地址改变之后,iframe的src地址并不会变更。

iframe – document.domain

假如两个窗口根域名相同,那么设置上面详情的document.domain属性,即可以规避同源政策,互相操作。

iframe – location.hash

location.hash是网页中#后面的部分,假如只是改变hash值,页面不会重新刷新。

// 父页面能把信息写入已知地址的iframe的hash中。document.getElementById('a').src = url + '#' + data;// iframe中通过监听hashchange事件收到信息。window.onhashchange = function () {  var message = window.location.hash;}// iframe改变父页面的hash地址parent.location.href = url + "#" + data;
iframe – window.name

window一个name属性,它最大特点是,无论能否同源都能读取它。
父窗口先打开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。
window.name = data;
接着,子窗口跳回一个与主窗口同域的网址。
location = ‘http://parent.url.com/xxx.html’;
而后,主窗口即可以读取子窗口的window.name了。
var data = document.getElementById(‘myFrame’).contentWindow.name;
这种方法的优点是,window.name容量很大,能放置非常长的字符串;缺点是必需监听子窗口window.name属性的变化,影响网页性可以。

// iframe页面window.name = 'I was there!';    // 这里是要传输的数据,大小一般为2M,IE和firefox下能大至32M左右                                 // 数据格式能自己设置,如json、字符串// 父页面var state = 0, iframe = document.createElement('iframe'),loadfn = function() {    if (state === 1) {        var data = iframe.contentWindow.name;    // 读取数据        alert(data);    //弹出'I was there!'    } else if (state === 0) {        state = 1;        iframe.contentWindow.location = "http://a.com/proxy.html";    // 设置的代理商文件    }  };iframe.src = 'http://b.com/data.html';iframe.onload  = loadfn;document.body.appendChild(iframe);
iframe – postMessage

上面两种方法都属于破解,HTML5为理解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为window对象新添加了一个window.postMessage方法,允许跨窗口通信,不管这两个窗口能否同源。这个方法可使用在与window.open打开的新页面进行通讯,或者者与iframe中的页面进行通讯。

// 这是iframe向父页面窗口发送消息。window.parent.postMessage('Hello World!', 'http://bbb.com');// 这是父页面向iframe窗口发送消息。document.getElementById("a").contentWindow.postMessage('Nice to see you', 'http://aaa.com');

postMessage方法的第一个参数是string格式的具体的信息内容,第二个参数是接收消息的窗口的源(origin),即”协议 + 域名 + 端口”,设置该值后,只会向固定域名的页面发送信息,用其余域名窗口打开当前iframe时,不会发送消息。也能设为*,表示不限制域名,向所有窗口发送。
父窗口和子窗口都能通过message事件,监听对方的消息。

window.addEventListener('message', function(e) {  // data是数据,origin是域名。这边最好也判断一下,能提升安全性  console.log(e.data, e.origin);});

localStorage

document.domain这种方法只适使用于 Cookie 和 iframe 窗口,LocalStorage 无法通过这种方法,而要用PostMessage API。

现有方案大多为用postMessage与iframe组合来传递localStorage。
父页面监听子页面传来的data,而后渲染到localStorage中。再子页面监听父页面传来的data,渲染到自己的localStorage中。

// 这是父页面发送消息的代码var data = JSON.stringify({key: 'storage', data: {name: ‘Jack’}});document.getElementsByTagName('iframe')[0].contentWindow.postMessage(data, 'http://bbb.com');// 这是子页面监听父页面发来的消息,并放置在localStorage中。window.onmessage = function(e) {  var payload = JSON.parse(e.data);  localStorage.setItem(payload.key, JSON.stringify(payload.data));};

子页面发送至父页面也同理。

AJAX

AJAX – 架设服务器代理商

架设服务器代理商(浏览器请求同源服务器,再由后者请求外部服务)
比方nginx的反向代理商能将请求直接转发出去,并且接收返回值。

AJAX – JSONP

JSONP是服务器与用户端跨源通信的常使用方法。最大特点就是简单适使用,老式浏览器一律支持,服务器改造非常小。
它的基本思想是,网页通过增加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入<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://a.com/ip?callback=foo');}function foo(data) {  console.log('Your public IP address is: ' + data.ip);};

上面代码通过动态增加<script>元素,向服务器a.com发出请求。注意,该请求的查询字符串有一个callback参数,使用来指定回调函数的名字,这对于JSONP是必须的。服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

// 服务器foo({"ip": "8.8.8.8"});

因为<script>元素请求的脚本,直接作为代码运行。这时,只需浏览器定义了foo函数,该函数就会立即调使用。

AJAX – WebSocket

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
它的最大特点就是,服务器能主动向用户端推送信息,用户端也能主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

但是严格地说,WebSocket技术不属于HTML5,这个技术是对HTTP无状态连接的一种革新,本质就是一种持久性socket连接,在浏览器用户端通过javascript进行初始化连接后,即可以监听相关的事件和调使用socket方法来对服务器的消息进行读写操作。与Ajax相比,Ajax技术需要用户端发起请求,而WebSocket服务器和用户端能彼此相互推送信息;XHR受到域的限制,而WebSocket允许跨域通信,这个特性导致我们至少能使用来做远控。

WebSocket实现了全双工通信,使WEB上的真正的实时通信成为可可以。浏览器和服务器只要要做一个握手的动作,而后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接能数据互相传送。在WebSocket协议中,为我们实现即时服务带来了三个好处:
1、用户端和服务器端之间数据传输时请求头信息比较小,大概2个字节。
2、服务器和用户端能相互主动的发送数据给对方。
3、不需要屡次创立TCP请求和销毁,节约宽带和服务器的资源。

具体能参考
WebSocket 教程 – 阮一峰
跨域(二)——WebSocket

AJAX – CORS

CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本处理方法。相比JSONP只可以发GET请求,CORS允许任何类型的请求。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功可以,IE浏览器不可以低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要使用户参加。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动增加少量附加的头信息,有时还会多出一次附加的请求,但使用户不会有感觉。
因而,实现CORS通信的关键是服务器。只需服务器实现了CORS接口,即可以跨源通信。

具体能参考 跨域资源共享 CORS 详解 – 阮一峰

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 前台跨域问题总结

发表回复