• 一文梳理同源策略与跨域技术


    1.同源策略

    同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

    1.1何谓同源

    如果两个 URL 的 protocolport (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。

    下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:

    URL 结果 原因
    http://store.company.com/dir2/other.html 同源 只有路径不同
    http://store.company.com/dir/inner/another.html 同源 只有路径不同
    https://store.company.com/secure.html 失败 协议不同
    http://store.company.com:81/dir/etc.html 失败 端口不同 ( http:// 默认端口是80)
    http://news.company.com/dir/other.html 失败 主机不同

    随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制。

    (1) Cookie、LocalStorage 和 IndexDB 无法读取。

    (2) DOM 无法获得。

    (3) AJAX 请求不能发送。

    虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。

    2.跨域

    2.1 何谓跨域?

    跨域问题是由于浏览器为了防止CSRF(跨站请求伪造)攻击,避免恶意攻击而带来的风险而采取的同源策略限制。当一个页面中使用XMLHTTPRequest对象发送HTTP请求时(XHR请求),必须保证当前页面和请求的对象是同源的

    能实现跨域的技术还是比较多的,篇幅有限,这篇文章主要给大家带来:

    • JSONP跨域
    • CORS跨域
    • postmessage
    • 服务器代理
    • WebSocket

    2.2 JSONP跨域

    JSONP的原理:静态资源请求不受同源策略影响。具体:浏览器只对XHR(XMLHttpRequest)请求有同源请求限制,而对script标签src属性、link标签ref属性和img标签src属性没有这种限制,利用这个“漏洞”就可以很好的解决跨域请求.

    JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调
    函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON数据。

    <script>
        function jsoncallback(response){
            console.log(response);
        }
        var script = document.createElement("script");
        script.src = "https://me.kervi.cn/v1/datas/jsondata.php?callback=jsoncallback";
        document.body.insertBefore(script, document.body.firstChild);
    </script>
    

    JSONP 是通过动态<script> 元素来使用的,使用时可以为src 属性指定一个跨域 URL。

    总结:

    • 简单易用
    • 能够直接访问响应文本,支持在浏览器与服务器之间双向通信
    • 仅支持GET请求(通过script标签的的src属性发送);
    • 需要后端配合,前后端约定一个字段名,这里约定的jsoncallback,来传递一个函数名,从而使得前端可以使用对应的callback函数,拿到数据,处理数据。
    • JSONP 是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码,而此时除了完全放弃 JSONP 调用之外,没有办法追究。因此在使用不是你自己运维的 Web 服务时,一定得保证它安全可靠;
    • 要确定 JSONP 请求是否失败并不容易。虽然 HTML5 给 <script> 元素新增了一个 onerror事件处理程序,但目前还没有得到任何浏览器支持。为此,开发人员不得不使用计时器检测指定时间内是否接收到了响应。但就算这样也不能尽如人意,毕竟不是每个用户上网的速度和带宽都一样。

    2.3 CORS跨域

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。

    CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

    在各种服务端代码实现如下:

    // 根据不同语言规则,具体语法有所不同,此处以NodeJs的express为例
    //设置跨域访问  
    app.all('*', function(req, res, next) {  
        res.header("Access-Control-Allow-Origin", "*");  
        res.header("Access-Control-Allow-Headers", "X-Requested-With");  
        res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
        next();  
    });   
    

    Nginx实现如下:

    server {
        ... 
        add_header Access-Control-Allow-Credentials true;
        add_header Access-Control-Allow-Origin $http_origin;
            
        location /file {
            if ($request_method = 'OPTIONS') {
                add_header Access-Control-Allow-Origin $http_origin;
                add_header Access-Control-Allow-Methods $http_access_control_request_method;
                add_header Access-Control-Allow-Credentials true;
                add_header Access-Control-Allow-Headers $http_access_control_request_headers;
                add_header Access-Control-Max-Age 1728000;
                return 204;
            }   
        }
        ...
    }
    

    2.4 postMessage

    「window.postMessage()」 方法可以安全地实现跨源通信。可以允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本文档,多窗口,跨域消息传递.多用于窗口间数据通信,这也使它成为跨域通信的一种有效的解决方案.

    兼容性:

    语法

    otherWindow.postMessage(message, targetOrigin, [transfer])

    • message 你要发送的信息(字符串和对象都可以)
    • targetOrigin 你要发送信息的目标域名
    • transfer 可选参数,与消息一起传输的Transferable对象序列。这些对象的所有权将提供给目标端,并且它们在发送端不再可用。

    已经有人写了不错的实践,博主这里就不做介绍,可以阅读postmessage可真太有用了了解。

    总结

    • postMessage是html5新增的一个解决跨域的方法,主要解决不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递,多用于页面与嵌套的iframe消息传递

    • 由于默认允许跨域,所以导致一些安全问题,主要攻击方式有两种,一是伪造数据发送端,易造成XSS,二是伪造数据获取端,类似JSONP劫持。

    • 用于接收消息的任何事件侦听器必须首先使用origin和可能的source属性检查消息发送者的身份。未能检查origin和可能的source属性可以实现跨站点脚本攻击。

    2.5 websocket

    WebSocket 是一种网络通信协议,可在网络浏览器和服务器之间建立“套接字”连接。这种方式本质没有使用了 HTTP 的响应头, 因此也没有跨域的限制。

    前端部分(代码来自秋风的笔记-10种跨域解决方案(附终极大招)

    <script>  let socket = new WebSocket("ws://localhost:8080");  socket.onopen = function() {    socket.send("秋风的笔记");  };  socket.onmessage = function(e) {    console.log(e.data);  };</script>复制代码
    

    后端部分

    const WebSocket = require("ws");const server = new WebSocket.Server({ port: 8080 });server.on("connection", function(socket) {  socket.on("message", function(data) {    socket.send(data);  });});
    

    总结

    • 建立在 TCP 协议之上,服务器端的实现比较容易。
    • 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
    • 数据格式比较轻量,性能开销小,通信高效。
    • 可以发送文本,也可以发送二进制数据。
    • 没有同源限制,客户端可以与任意服务器通信。
    • 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

    2.6 Nginx反向代理

    这里需要说明的是: 跨域是浏览器行为,不是服务器行为。同源策略仅是针对浏览器的安全策略。服务器端调用HTTP接口只是使用HTTP协议,不需要同源策略,也就不存在跨域问题。

    实际上,请求已经到达服务器了,只不过在回来的时候被浏览器限制了

    实现思路:通过Nginx配置一个代理服务器域名与发出请求域名相同,端口不同,反向代理访问目标域名。

    背景:domain1需要跨域访问domain2

    server {
            listen 80;
            server_name www.domain1.com;
            location / {
                proxy_pass www.domain2.com:8080;
            }
    }
    

    需要说明的是,前端跨域的技术还有许多,只是限于篇幅没有讲到,比如node正向代理,window.name+iframe等。还想了解别的跨域方案的小伙伴可以看本文的参考文章去观摩观摩。

    小结

    同源策略仅仅是针对浏览器的安全策略,跨域是浏览器行为,如果两个 URL 的 protocolport (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。现在有许多的跨域方案可供大家选择,本文仅仅选择了JSONP、CORS、postMessage等6种跨域技术进行了阐述,希望能在梳理自己知识点的同时帮助到一些人。

    参考文章:

    jsonp完美解决跨域问题,简单

    跨域解决方案实践cors及jsonp

    跨资源共享cors详解-阮一峰

    浏览器同源政策及其规避方法-阮一峰

    postmessage滥用导致的安全问题

    10种跨域解决方案(附终极大招)

    websocket教程-阮一峰

    9种常见的前端跨域解决方案

  • 相关阅读:
    Bootstrap 实战之响应式个人博客 (一)
    观察者(发布——订阅)模式
    迭代器模式
    代理模式
    策略模式
    单例模式
    CSS3 媒体记
    CSS3 动画记
    css3 过渡记
    CSS3 变形记
  • 原文地址:https://www.cnblogs.com/rainbowly/p/13251550.html
Copyright © 2020-2023  润新知