浏览器的同源策略和跨域

94 阅读2分钟

浏览器的同源策略

同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。

它能帮助阻隔恶意文档,减少可能被攻击的媒介。例如,它可以防止互联网上的恶意网站在浏览器中运行 JS 脚本,从第三方网络邮件服务(用户已登录)或公司内网(因没有公共 IP 地址而受到保护,不会被攻击者直接访问)读取数据,并将这些数据转发给攻击者。

1、什么是同源策略

如果两个 URL 的协议、域名和端口 (en-US)(如果有指定的话)都相同的话,则这两个 URL 是同源的。

2、浏览器有同源策略,我们为什么要跨域呢

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。 在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问问题。在请求的过程中我们要想回去数据一般都是post/get请求,所以..跨域问题出现。

3、实现跨域的方式有哪些

3.1、jsonp

JSONP(JSON with Padding)是JSON的一种补充使用方式,不是官方协议,而是利用 Script 标签请求资源可以跨域的特点,来解决跨域问题的,是一种变通的解决方案。

<html>
  <body>
    <div>
      receive <span id="qwerty"> </span>
    </div>
  </body>
  <script>
    function callfun(data) {
      document.getElementById('qwerty').innerHTML = data;
    }
  </script>
  <script src="http://127.0.0.1:10010/js?call=callfun"></script>
</html>


服务端代码
//后端使用的egg.js,核心代码只有ctx.body那一句
'use strict';

const Controller = require('egg').Controller;
class JsonpController extends Controller {
  async index() {
    const { ctx } = this;
    console.log(ctx.query);
    ctx.set('content-type', 'text/javascript');
    ctx.body = ctx.query.call + '("nihao")';
  }
}


3.2postMessage

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

页面a

<!DOCTYPE html>
<html>
<head>
    <title>A域=>postMessage跨域实践</title>
</head>
<body>
    <input id="data" type="text" name="" value="">
    <button id="post">点击发送</button>
</body>
<script type="text/javascript">
    var ifr = document.createElement("iframe")
        ifr.style.display="none";
        ifr.src="http://top.jiangqi.cn:8081/index3.html"
    post.onclick=function(){
        var data = document.getElementById("data").value;
        document.getElementsByTagName("head")[0].appendChild(ifr);
        ifr.onload = function(){
            ifr.contentWindow.postMessage(JSON.stringify(data),"http://top.jiangqi.cn:8081/index3.html")
        }
    }
    window.addEventListener("message",function(e){
     console.log(e)
        console.log(e.data)
    },false)

</script>
</html>

页面b

<!DOCTYPE html>
<html>
<head>
    <title>B域=>postMessage跨域实践</title>
</head>
<body>

</body>
<script type="text/javascript">
    window.addEventListener("message",function(e){
        if(JSON.parse(e.data)){
            window.parent.postMessage("我已经收到data:"+e.data,"http://www.jiangqi.cn/index3.html")
        }
    },false)
</script>
</html>

3.3websocket

WebSockets 是一种先进的技术。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此 API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。

<script>
  var ws = new WebSocket('ws://localhost:8080')

  ws.onopen = function (mevt) {
    console.log('客户端已连接')
  }
  ws.onmessage = function (mevt) {
    console.log('客户端收到消息: ' + mevt.data)
    // ws.close()
  }
  // ws.onclose = function (mevt) {
  //   console.log('连接关闭')
  // }

</script>

服务端

const { WebSocketServer } = require('ws')
const wss = new WebSocketServer({
  port: 8080
})
wss.on('connection', (ws, req) => {
  console.log('客户端已连接:', req.socket.remoteAddress)
  ws.on('message', data => {
    console.log('收到客户端发送的消息:', data)
  })
  setInterval(() => {
    ws.send('我是服务端') // 向当前客户端发送消息
  }, 5000);
})