浏览器相关-跨域

2020-04-09 23:26:2910/1/2021, 3:34:43 AM

WHAT-什么是跨域及同源策略

同源策略

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

如果两个 URL 的 protocolport (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。

同源策略限制内容有:

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求发送后,结果被浏览器拦截了

但是有三个标签是允许跨域加载资源:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

跨域

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源就算做跨域

特别说明:

  1. 如果是协议和端口造成的跨域问题,前端是无能为力的

  2. 在跨域问题上,仅仅是通过URL的首部来识别而不会根据域名对应的ip是否相同来判断。

  3. 请求跨域后,请求到底有没有发送出去:

    跨域不是请求发送不出去,请求能发送出去,服务端能接收到请求并正常的返回,只是结果被浏览器拦截了(同源策略)。

  4. 为什么通过表单的方式可以发起跨域请求,Ajax就不能?

    归根结底,跨域是因为了阻止用户读取到另一个域名下的内容,Ajax可以获取响应,浏览器任务这不安全所以拦截了响应;但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

WHY-为什么有同源策略

安全

HOW-跨域解决方案

JSONP

原理:利用<script>标签没有同源策略限制的漏洞,网页可以得到从其他源动态产生的JSON数据。JSONP请求一定需要对方的服务器支持。JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。

function jsonp({ url, params, callback }) {
    return new Promise((resolve, reject) => {
        let script = document.createElement("script")
        window[callback] = function(data) {
            resolve(data)
            document.body.removeChildren(script)
        }
        params = { ...params, callback }
        let arrs = []
        Object.keys(params).forEach(item => arrs.push(`${ key }=${ params[key] }`))
        script.src = `${ url }?${ arrs.join('&') }`
        document.body.appendChild(script)
    })
}

CORS

CORS需要浏览器和后端同时支持

浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。

服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。

虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求复杂请求

简单请求

只要同时满足以下条件,就属于简单请求:

  1. method=GET/POST/HEAD
  2. Content-Type=text/plain或multipart/form-data或application/x-www-form-urlencoded
  3. 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问

复杂请求

复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为预检请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

postMessage

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递

websocket

Websocket是HTML5的一个持久化协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

Nginx反向代理

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。