跨域

作者: 奔跑的兔子_ | 来源:发表于2019-08-09 16:44 被阅读0次

关于跨域

什么是同源策略?

同源策略/SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。

跨域通信:js 进行 DOM 操作、通信时如果目标与当前窗口不满足同源条件,浏览器为了安全会阻止跨域操作。

跨域通信的方法:

一. CORS 跨域

概念

CORS(Cross-Origin Resource Sharing 跨源资源共享),当一个请求 url 的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。

用法

- 在 a 页面,new 一个 XMLHttpRequest(),因考虑浏览器兼容问题,先判断浏览器是否为 ie,如下 function1;
- 然后调用 open 函数 初始化 HTTP 请求参数,但是并不发送请求。
open 语法

open(method, url, async, username, password)
// method为请求方式,值包括 GET、POST 和 HEAD;
// url 参数是请求的主体
// async 参数请求使用应该异步地执行,false就是等待有返回数据的时候再继续往下走,还没有得到数据的时候就会卡在那里,直到获取数据为止。如果这个参数是 false,请求是同步的,后续对 send() 的调用将阻塞,直到响应完全接收。如果这个参数是 true 或省略,请求是异步的,且通常需要一个 onreadystatechange 事件句柄。
// username 和 password 参数是可选的,为 url 所需的授权提供认证资格
// [详细](http://www.w3school.com.cn/xmldom/dom_http.asp)

;。)
true 就是不等待,直接返回,这就是所谓的异步获取数据!

<!--页面a (http://localhost:3000)-->
    <button>通过CROS跨域</button>
    <p>hello world 😘</p>
    <script>
        // function1
        function createXmlHttpRequest(){
            if(window.ActiveXObject){ //如果是IE浏览器
                return new ActiveXObject("Microsoft.XMLHTTP");
            }else if(window.XMLHttpRequest){ //非IE浏览器
                return new XMLHttpRequest();
            }
        }
        var btn = document.getElementsByTagName('button')[0];
        var text = document.getElementsByTagName('p')[0];
        btn.addEventListener('click', function () {
            var xhr = createXmlHttpRequest();
            xhr.open('GET', 'http://localhost:3001', true); // 与3001端口建立一个连接
            xhr.send(null); // 发送给3001端口数据为空
            xhr.onreadystatechange = () => { // 请求状态改变后调用这个函数
                if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // 如果请求成功
                    text.innerHTML = xhr.response;// 处理数据
                }
            }
        })
    </script>
</body>
// 页面b (http://localhost:3001)
app.get("/", (req, res) => {
  res.set("Access-Control-Allow-Origin", "http://localhost:3000"); // 设置允许跨域的origin,允许3000端口访问本端口(3001)
  res.send("Hello world from CROS.");
});
安全隐患:

跨域请求和 Ajax 技术都会极大地提高页面的体验,但同时也会带来安全的隐患,其中最主要的隐患来自于 CSRF(Cross-site request forgery)跨站请求伪造。

CSRF 攻击的大致原理
  1. 用户通过浏览器,访问正常网站 A(例如某银行),通过用户的身份认证(比如用户名/密码)成功 A 网站。
  2. 网站 A 产生 Cookie 信息并返回给用户的浏览器;
  3. 用户保持 A 网站页面登录状态,在同一浏览器中,打开一个新的 TAB 页访问恶意网站 B;
  4. 网站 B 接收到用户请求后,返回一些攻击性代码,请求 A 网站的资源(例如转账请求);
  5. 浏览器执行恶意代码,在用户不知情的情况下携带 Cookie 信息,向网站 A 发出请求。
  6. 网站 A 根据用户的 Cookie 信息核实用户身份(此时用户在 A 网站是已登录状态),A 网站会处理该请求,导致来自网站 B 的恶意请求被执行。

二. JSONP 跨域

JSONP 跨域的原理

在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但 img、iframe、script 等标签是个例外,这些标签可以通过 src 属性请求到其他服务器上的数据。利用 script 标签的开放策略,我们可以实现跨域请求数据,当然,也需要服务端的配合。当我们正常地请求一个 JSON 数据的时候,服务端返回的是一串 JSON 类型的数据,而我们使用 JSONP 模式来请求数据的时候,服务端返回的是一段可执行的 JavaScript 代码。

<!--页面a (http://localhost:3000)-->
<body>
    <p>hello worlda</p>
    <script>
        function myFunctionA(data) {
            alert('获取数据成功,2s后改变数据!')
            console.log(data);
            let p = document.getElementsByTagName('p')[0]
            setTimeout(function () {
                p.innerHTML = data.message
            }, 2000)
            // 2s后p标签内的内容将改变
        }
    </script>
    <script src="http://localhost:3001?callback=myFunctionA"></script>
    <!--在src里面的问号?后面的参数({callback: 'myFunction'})可以在3001端口页面中可以通过req.query.callback获取-->
</body>
// 页面b (http://localhost:3001)
app.get("/", function(req, res) {
  var callbackName = req.query.callback; // myFunctionA
  res.send(callbackName + "({'message': 'hello world from JSONP!'});");
  // myFunction({'message': 'hello world from JSONP!'})
  // 一个带参数的执行函数
});

三. postMessage 跨域

用法:

- IFrame是从document取得的,即作作为document的子对象出现,虽然是文档(document)对象,但由于它是独立的页面,因而拥有自己的事件,拥有自己的窗口对象(contentWindow);

<!--页面a (http://localhost:3000)-->
<body>
    <div id="father">
        <p>这里3000端口</p>
        <input type="text"/>
        <button>发送信息</button>
        <p style="text-align: left;">message :  <span></span></p>
    </div>
    <iframe id="child" src="http://localhost:3001"></iframe>
    <script>
        var input = document.getElementsByTagName('input')[0];
        var span = document.getElementsByTagName('span')[0];
        var btn = document.getElementsByTagName('button')[0];
        var frame = document.getElementById('child').contentWindow;

        btn.onclick = function () {
            var msg = input.value;
            frame.postMessage('收到信息:' + msg + ' --from 3000 port!😨', 'http://localhost:3001');
        }
        function receiveMessage (event) {
            if (event.origin !== 'http://localhost:3001') {
                return false
            }
            var data = event.data;
            span.innerHTML = data;
        }
        window.addEventListener('message', receiveMessage, false);
    </script>
</body>

四. window. name 跨域

五. location.hash 跨域

六. document.domain 跨域

七. 后端设置代理 proxy 跨域

八. WebSocket 跨域

相关文章

网友评论

      本文标题:跨域

      本文链接:https://www.haomeiwen.com/subject/nxmibftx.html