Skip to content

跨域访问 #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Twlig opened this issue Feb 24, 2022 · 0 comments
Open

跨域访问 #8

Twlig opened this issue Feb 24, 2022 · 0 comments
Labels

Comments

@Twlig
Copy link
Owner

Twlig commented Feb 24, 2022

同源策略

同源策略是浏览器最核心也最基本的安全功能。保证用户信息的安全,防止恶意的网站窃取数据。对于不同源的站点之间的相互请求会做限制。

同源策略需同时满足的三个要求:

  • 协议相同
  • 域名相同
  • 端口相同
http:www.test.com与https:www.test.com 不同源——协议不同
http:www.test.com与http:www.admin.com 不同源——域名不同
http:www.test.com与http:www.test.com:8081 不同源——端口不同

如果非同源,共有三种行为受到限制:

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. DOM 无法获得
  3. AJAX 请求不能发送

注意:跨域限制仅仅是浏览器的行为,通过代理服务器,或者其他工具发送请求就能轻松绕过

跨域流程

  • 浏览器端
    假设我们点击一个按钮去获取数据,获取数据的请求准备从浏览器发出,这时浏览器先会检测这条请求是同源还是跨域,也就是与按钮所在页面的地址是同源还是跨域,如果是同源,好说,直接发送出去;如果是跨域的请求,那就得hold住先,浏览器会在请求的http header中加上一个Origin字段,标明这个请求是从哪里发出来的,例如: Origin:http://neighbour.com:9000/

  • 服务器端
    服务器收到请求会给与响应,响应的header里写明跨域的配置信息,告诉浏览器,它允许哪些域名发来的请求访问,哪些method可以执行。浏览器收到响应后自动判断能不能真正执行请求。

  • 跨域流程

    1. 页面发送请求。
    2. 浏览器根据同源策略做出判定,如果是同源请求,直接发送出去;如果是跨域请求,在HTTP HEADER加上Origin字段,或是先发送一次预检请求(preflight)。
    3. 服务器接收请求,根据自身跨域的配置(如允许哪些域名,什么样的Method访问),返回文件头。若未配置过任何允许跨域,则文件头里不包含Access-Control-Allow-origin字段,若配置过域名,则返回Access-Control-Allow-origin+ 对应配置规则里的域名的方式。
    4. 浏览器接收到响应,根据响应头里的Access-Control-Allow-origin字段做匹配,如果没有这个字段,说明不匹配;如果有,将字段内容和当前域名做比对。如匹配,则可以发送请求。

跨域请求类型

​ 浏览器在发送跨域请求的时候会判断一下是简单请求还是非简单请求,简单请求:先执行后判断是否跨域。非简单请求浏览器则会先发送一次OPTIONS预检请求,根据预检请求的结果,决定是否正式发送请求。

  1. 简单请求

    • 方法仅限于 HEAD,GET或POST
    • 无自定义头
    • Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain (没有application/json, 如果发送JSON格式的body请求数据是一个非简单请求)
  2. 非简单请求

    除上述简单请求之外都是非简单请求

跨域解决方案

跨域问题在前端和后端都有解决方案。有以下两点值得注意:

  1. 如果是协议和端口造成的跨域问题“前台”是无能为力的
  2. 在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的IP地址对应着两个域或两个域是否在同一个IP上

前端解决方案

  1. document.domain + iframe跨域

    此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过JS强制设置document.domain为基础主域,就实现了同域。

  2. location.hash + iframe跨域

    实现原理: a与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接JS访问来通信。

    具体实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象

  3. window.name + iframe跨域

    window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)

    通过iframesrc属性由外域转向本地域,跨域数据即由iframewindow.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

  4. postMessage跨域

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

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

    用法postMessage(data,origin)方法接受两个参数:

    • data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
    • origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
  5. 动态创建script

    script标签不受同源策略的限制

  6. 代理服务器

    由于同源策略是对浏览器和外域服务器的限制,如果是代理到本地服务器处理,然后由本地服务器与外域服务器通信,再由本地服务器转向浏览器,就可以绕过同源策略。处理的方法有Vue设置代理,或者Nginx,或者后端设置一个代理都可以。

  7. jsonp

    jsonp的原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。只支持GET请求。后端也需要配置jsonp。

后端解决方案

  1. 跨域资源共享(CORS)

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

    后端设置Access-Control-Allow-Origin响应头字段即可。

  2. WebSocket协议跨域

    浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。

参考博客:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant