跨源网络访问

2018-09-17  本文已影响31人  igor_d140

链接:浏览器的同源策略
链接:跨域资源共享
链接:跨域共享数据的十种方法
链接:前端跨域问题及其解决方案

广义的跨域:
1.) 资源跳转: A链接、重定向、表单提交
2.) 资源嵌入: <link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链
3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

跨源网络访问特点
允许跨域写、资源嵌入 写:(链接links,重定向以及表单提交...)。内嵌资源(可读取嵌入图片的高度和宽度...)
不允许跨域读
可用于嵌入跨源的标签
标签
script跨域脚本 语法错误信息只能在同源脚本中捕捉到
link css CSS跨域需要设置正确的Content-Type 消息头
img 嵌入图片 图片格式包括PNG,JPEG,GIF,BMP,SVG,...
videoaudio 多媒体资源
objectembedapplet 插件
@font-face 浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)
frameiframe 可载入任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。
... ...
跨域资源共享(cross-origin sharing)

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

CORS
方式 如:XMLHttpRequest、Fetchs使用CORS,以降低跨域HTTP请求所带来啊的风险
限制 CORS需要客户端和服务端同时支持
共享范围 XMLHttpRequest、Fetch发起的HTTP请求。Web字体@font-face。WebGL贴图。媒体资源画面绘制Images/video绘制到canvas。样式表。Scripts
常见跨域方案
方案
JSONP跨域 jsonp是利用script标签可嵌入跨源的特性。嵌入的资源为js脚本(实际是动态对上文存在函数的实例化),仅支持get
Flash URLLoader 通过flash发送HTTP请求(iOS不支持)
cross-origin sharing(CORS) 服务端设置白名单Access-Control-Allow-Origin: [域名白名单],客户端通过XMLHTTPRequest /Fetch/XDomainRequest(IE8)请求
server proxy nginx/nodejs/apache...代理
document.domain + iframe 父子域,兄弟域场景。设置document.domain为同样值(或基础主域)
location.hash + iframe FIM – Fragment Identitier Messaging a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信
window.name + iframe name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)
postMessage 页面与新窗口,多窗口之间,页面与iframe信息交互
WebSocket协议跨域 浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现
Flash LocalConnection SWF之间通过进程通信
Cross Frame Cross Frame是FIM的一个变种,它借助了一个空白的iframe

JSONP实际是动态对上文存在函数的实例化

<script>
    function setTitle(title) {
      return title ?  document.querySelector('title').innerHTML = title : 0
    }
    function setName(name) {
      return name ?  document.getElementById('name').innerHTML = name : 0
    }
  ...
</script>
  <script src="https://www.jianshu.com/...."></script> // 异步返回setTitle('跨源网络访问')  ,setName('可返回N多个')  ......

document.domain + iframe 解决跨域
1.)父窗口:(http://www.domain.com/a.html)<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
    document.domain = 'domain.com';
    var user = 'admin';
</script>复制代码2.)子窗口:(http://child.domain.com/b.html)<script>
    document.domain = 'domain.com';
    // 获取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user);
</script>



这种方式适用于主域相同,子域不同,比如http://www.a.com和http://b.a.com
假如这两个域名下各有a.html 和b.html,

a.html

    document.domain = "a.com";
    var iframe = document.createElement("iframe");
    iframe.src = "http://b.a.com/b.html";
    document.body.appendChild(iframe);
    iframe.onload = function() {
        console.log(iframe.contentWindow....); // 在这里操作b.html里的元素数据
    }

b.html

    document.domain = "a.com";

注意:document.domain需要设置成自身或更高一级的父域,且主域必须相同。

postMessage

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:a.) 页面和其打开的新窗口的数据传递b.) 多窗口之间消息传递c.) 页面与嵌套的iframe消息传递d.) 上面三个场景的跨域数据传递用法:postMessage(data,origin)方法接受两个参数data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

WebSocket协议跨域

WebSocket协议跨域WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。1.)前端代码:<div>user input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');

// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg); 
    });

    // 监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('Server socket has closed.'); 
    });
});

document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>复制代码2.)Nodejs socket后台:var http = require('http');
var socket = require('socket.io');

// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

// 监听socket连接
socket.listen(server).on('connection', function(client) {
    // 接收信息
    client.on('message', function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });

    // 断开处理
    client.on('disconnect', function() {
        console.log('Client socket has closed.'); 
    });
});




跨源访问

同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest<img> 标签时则会受到同源策略的约束。这些交互通常分为三类:

以下是可能嵌入跨源的资源的一些示例:

跨源数据存储访问

存储在浏览器中的数据,如localStorageIndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Javascript脚本不能对属于其它源的数据进行读写操作。

Cookies 使用不同的源定义方式。一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(public suffix)即可。Firefox 和 Chrome 使用 Public Suffix List 决定一个域是否是一个公共后缀(public suffix)。Internet Explorer使用其自己的内部方法来确定域是否是公共后缀。不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名(sub-domains) 访问 cookie。设置 cookie 时,你可以使用Domain,Path,Secure,和Http-Only标记来限定其访问性。读取 cookie 时,不会知晓它的出处。 即使您仅使用安全的https连接,您看到的任何cookie都可能使用不安全的连接进行设置。

如何允许跨源访问

使用 CORS 允许跨源访问。

如何阻止跨源访问
跨源脚本API访问

avascript的APIs中,如 iframe.contentWindow, window.parent, window.openwindow.opener 允许文档间直接相互引用。当两个文档的源不同时,这些引用方式将对 WindowLocation对象的访问添加限制,如下两节所述。

为了在不同源中文档进一步交流,可以使用window.postMessage

Window

规范: http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#security-window.

允许以下对 Window 属性的跨源访问:

方法:

window.blur
window.close
window.focus
window.postMessage

属性
window.closed 只读.
window.frames 只读.
window.length 只读.
window.location 读/写.
window.opener 只读.
window.parent 只读.
window.self 只读.
window.top 只读.
window.window 只读.
Location

Specification: http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#security-location.

允许以下对 Location 属性的跨源访问:
location.replace
URLUtils.href

原文链接

上一篇下一篇

猜你喜欢

热点阅读