一文读懂 CORS 跨域

前端开发经常会遇到跨域问题,通过搜索基本都能解决,或者直接交给后端处理,只要浏览器不要再报下面的错误就行。

XMLHttpRequest cannot load api.example.com. No
‘Access-Control-Allow-Origin’ header is present on the requested
resource. Origin ‘http://localhost:8100’ is therefore not allowed
access.

在解决这个问题后,我还是感觉云里雾里,阅读了很多资料,最终认为自己“理解”了,以下是我的理解内容:

浏览器为了用户数据安全,默认不允许跨域。只要 XMLHttpRequest
发起请求的源和浏览器地址栏中的源不一致,请求就会被限制。解决办法是采用跨域资源访问(CORS),后端在 Response Header中写入 Access-Control-Allow-Origin: * 。

后来又查了一下 Access-Control-Allow-Origin 的作用,发现这个理解有点肤浅。
关于跨域我提出了如下几个问题:

  • 什么是用户数据,它存在哪里?
  • 为什么用户数据在浏览器中会不安全?
  • 为什么要跨域?是谁阻止了跨域?
  • 跨域的主体是谁?跨域了能做什么?
  • 实现跨域后,用户数据会不会不安全?

如果对以上问题存在疑惑,希望这篇文章能为你解答。
在讲跨域前,我们需要了解一点基础知识。

HTTP 前瞻

浏览器通常是基于 HTTP 协议和 Web 服务器通信的,因为 HTTP 协议无状态的特性,浏览器会在本地存储服务端发来的 Cookie,在下次发送请求时,带上 Cookie 来表明自己的身份,Cookie 就属于用户数据。

为了提高 HTTP 通信的效率,HTTP 设计了缓存策略,用来缓存 Response 数据,下次发起同样的请求时,会尝试使用本地缓存,来加快请求速度,减小服务器压力。

HTTP Respone 中可能会携带用户敏感信息。

浏览器能访问不同的网站,用户数据原本存在各自的远端服务器,但如果用户数据支持本地缓存,就会共处于浏览器缓存中。访问银行网站,会缓存银行卡、手机号等信息;看小电影,会缓存一些小电影的元数据。

这些数据都能被浏览器访问,那如何保证小电影网站的 JS 代码,不会偷偷读取银行网站缓存的用户数据,然后上传到它们后台呢?

同源策略

浏览器会对访问本地数据的 JS 进行监管,想要获取本地数据,就需要携带身份信息,默认只允许 JS 访问和它同源的数据,这就是同源策略。

浏览器在存储用户数据时,会标记数据的来源(Origin)。当 JS 脚本访问本地数据时,会检查它的源是否和用户数据关联的源一致,不一致就会拒绝访问。

JS 和 HTML 是同源的,即显示在浏览器地址栏中的 Scheme + Host + (Port)。

A 网站在发起 XMLHttpRequest 请求时,浏览器会在该请求的 Header 中添加 Origin: A 字段,来表明请求者的身份。需要注意这里的 A 并不是 XMLHTTPRequest 的 Host,而是 JS 文件的来源。

在这里插入图片描述

浏览器会先检查本地是否存在该请求的 Response 缓存,如果存在并且缓存未失效,会验证 JS 的来源,也就是 XMLHttpRequest Header 中的 Origin 字段。

上图中 XMLHttpRequest 请求的源是 http://testdrive.dasouche.net ,如果该请求之前已经发起成功过,本地会存在它的 Response 缓存,并且缓存会有这个源标记。

Request Header 携带的源(Origin)是 http://f2e.su.dasouche.net ,它代表 JS 文件的来源,浏览器检查到它与缓存的源不一致,会拒绝访问 Response,并抛出 XMLHttpRequest 请求异常。

上面的例子,看上去不太合理,如果请求从来没有成功过,就不会存在缓存。

其实如果本地没缓存, XMLHttpRequest 简单请求依然会发出去,并且会把 Response 写入了缓存(如果允许的话),之后浏览器才会根据以上同源策略,控制缓存的读取。

CORS 跨域

在实际开发中,请求 HTML/JS 资源的源,可能和 XMLHttpRequest 请求不同源。跨域就是为了突破浏览器同源策略的限制。

JS 想要跨越它的来源限制,去访问 XMLHttpRequest 请求的 Response 数据。所以严格来讲跨域的说法并不准确,准确的说法应该叫跨源。

实现跨域的方法有很多,比如有 JSONP、WebSocket、CORS 等。我们来看看最常见的 CORS 是如何实现跨域的。
CORS 全称跨源资源共享(Cross-Origin Resource Share),也就是通过某种机制来共享数据。

服务端在返回 Response 时,默认只允许同源的 JS 访问,如果服务端在 HTTP Response 中附加一个白名单,标记允许哪些域访问该资源,就允许了跨域访问。

这个白名单就是响应头 Access-Control-Allow-Origin。

浏览器会允许 Access-Control-Allow-Origin 白名单中的域访问 Response,如果是 Access-Control-Allow-Origin: * 就表示允许任何域访问该 Respone,这是存在安全隐患的。

如果恶意网站制造一个和银行网站一模一样的请求,本地 Response 缓存没有访问权限控制,浏览器会傻傻的把响应数据交给这个恶意网站。

所以对于用户数据敏感接口,最好还是不要开启允许任意域访问,而是采用白名单机制。

小结

同源策略在浏览器端保证用户数据的安全,但它也给同一个网站不同域请求的数据共享带来不便。

因此就有了跨域的需求,跨域的方法有很多,本文主要介绍了 CORS 跨域,以及它的原理。

虽然同源限制来自于浏览器,但 CORS 允许跨域的开关掌握在服务端。这样即保证了用户数据的安全,又实现了数据的共享,可谓一举两得。

原文链接:https://juejin.im/post/5e72bd8b51882549165435f1

发布了227 篇原创文章 · 获赞 41 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_42554191/article/details/104962266