zoukankan      html  css  js  c++  java
  • 跨域

    跨域

    如果协议、域名或者端口有一个不同就是跨域。

    同源策略

    推荐阅读:浏览器同源政策及其规避方法

    因为浏览器出于安全考虑(主要用来 防止信息泄露 和 CSRF 攻击),制定了同源策略,意思就是跨域时 Ajax 请求会失败。

    问题:

      然而同源策略还是不能完全阻止 CSRF,它只是把 Response 给拦截了,就是请求还是发出去了。

      换句话说只能阻止获取 Response 的信息,不能阻止发送请求

    例子:

      有个恶意网站,一打开就会跨域发送这样一个请求,ajax 直接发出去 https://xxx.com/trade?money=1000&userId=666 (xhr.withCredentials = true 时还会带上cookie)

      虽然 xhr 的 response 恶意网站收不到,但是这个请求确确实实发出去了

    结论:

      因此,真正的安全应该在服务端做好。例如,cookie 和 ip 绑定、检查 reference、用 token 来替代 cookie,这些都是解决csrf 的方法。

    跨域请求

    因为同源策略的存在,我们不得不通过一些手段,去实现跨域请求。

    我知道的有以下8种:JSONP、CORS、WebSocket、postMessage、hashchange、window.name、代理、document.domain

    JSONP

      利用 script、img 的 src 不受同源策略限制的特点,发送跨域的 GET 请求。

      实现这个需要前后端都改写

      例如:

    <script src="http://domain/api?param1=a&param2=b&callback=xxx"></script>
    <script>
    function xxx(data) {
        console.log(data)
    }
    </script>
    GET  http://domain/api?param1=a&param2=b&callback=xxx 会返回这样的
    xxx({
        errCode: 0,
        data: {
            list: [{age: 1}, {age: 2}, {age: 3}, {age: 4}, {age: 5}],
            page: 1,
            size: 5,
            total: 100
        }
    })

    上面定义的全局函数xxx,就可以接受到服务器返回的 data 了

    CORS

    Cross-origin resource sharing 跨域资源分享

    这个十分简单,只需要后端改写一下,加几个 Access-Control-Allow-xxx 的响应头就可以了。前端完全不用修改,跨域请求当作正常请求来发送就可以了。

    很早之前就写过博文了,这里就不细说了:Ajax跨域CORS

    WebSocket

    普通版 ws:// 和 加密版 wss://,这个协议不受同源策略限制,因此可以跨域。

    postMessage

    通过 window.open 或者 iframe.contentWindow 拿到的 window 对象可以用 postMessage 来通讯,这个不需要 document.domain 一致,都可以通讯。

    这个纯前端就能做到,推荐阅读:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

    // 发送方
    let otherWin = window.open('https://www.qq.com');
    otherWin.postMessage('信息xxx', '*');
    
    // 接收方
    window.addEventListener('message', ev => {
        console.log(ev.data);
    })

    hashChange

    H5之前,和 iframe 通讯可以用 hashChange 事件来实现跨域通讯

    // 设置iframe的hash
    var src = originURL + '#' + data;
    document.getElementById('myIFrame').src = src;
    
    // iframe 监听 hashchange 事件
    window.onhashchange = function () {
        var data = window.location.hash;
    };

    window.name

    window.name有个特性,就是可以继承上一个页面的window.name

    利用这个特性 + iframe,可以跨域通讯。

    iframe 访问异域网站,异域网站脚本设置 window.name

    iframe src 设置为同域页面,这个页面就继承了之前设置的 window.name

    这时候iframe和主页面,就不存在跨域了,可以正大光明地拿到 iframe.contentWindow.name

    代理

    起一个代理服务器,例如配置一个 Nginx ,如果需要跨域的请求,就发送成特定的域内请求,靠后台识别,代理到指定的服务器。最常用的就是 webpack-dev-server 的 proxy(就是 express 的 http-proxy-middleware)。

    document.domain

    document.domain 如果能设置成一致的话,2个页面就可以通过 iframe 或者 window.open,互相操作dom。

    当然 document.domain 只能设置成自己或者比自己更高级的域名,例如 xxx.qq.com 只能设置成 xxx.qq.com 或者 qq.com

    这个纯前端就能做到, 但是这个不是传统意义的跨域通讯,而是跨域修改dom

    // iframe 
    // 拿到 iframe 的 window
    document.querySelector('iframe').contentWindow
    // iframe 也能拿到 宿主的window
    window.parent
    
    // window.open 返回值就是打开页面的 window
    let openedWin = window.open('https//www.cnblogs.com');
    // 被打开的可以通过 window.opener 获取打开者
    window.opener

    但是如果 document.domain 不一致,就会报跨域的错。

     ps:www.baidu.com 和 baidu.com 是跨域吗?

    是的,但是如果document.domain都设置为baidu.com,那就可以跨域互相请求了。

  • 相关阅读:
    Qt5:快速设计对话框 QtDesigner 的使用
    Qt5:为菜单项添加图标 、 快捷键 和 状态栏 提示
    Qt5:在窗口上创建菜单栏
    Qt5:主窗口的创建 子类化QMainWindow
    AltiumDesigner设计快速入门
    AT24C02的MSP430驱动
    DSP_Builder设计方法说明_SinWave
    矩阵按键的MSP430驱动函数
    DAC8552使用说明
    PS2的FPGA解码模块
  • 原文地址:https://www.cnblogs.com/amiezhang/p/11410006.html
Copyright © 2011-2022 走看看