浏览器相关-跨域
WHAT-什么是跨域及同源策略
同源策略
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
如果两个 URL 的 protocol、port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。
同源策略限制内容有:
- Cookie、LocalStorage、IndexedDB 等存储性内容
- DOM 节点
- AJAX 请求发送后,结果被浏览器拦截了
但是有三个标签是允许跨域加载资源:
<img src=XXX>
<link href=XXX>
<script src=XXX>
跨域
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源就算做跨域。
特别说明:
如果是协议和端口造成的跨域问题,前端是无能为力的
在跨域问题上,仅仅是通过URL的首部来识别而不会根据域名对应的ip是否相同来判断。
请求跨域后,请求到底有没有发送出去:
跨域不是请求发送不出去,请求能发送出去,服务端能接收到请求并正常的返回,只是结果被浏览器拦截了(同源策略)。
为什么通过表单的方式可以发起跨域请求,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 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求和复杂请求。
简单请求
只要同时满足以下条件,就属于简单请求:
- method=GET/POST/HEAD
- Content-Type=text/plain或multipart/form-data或application/x-www-form-urlencoded
- 请求中的任意
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写入,实现跨域登录。