什么是 CORS(跨源资源共享)?
CORS(跨源资源共享)是一种基于HTTP并由Web浏览器控制的安全机制。它允许客户端请求来自自身以外源(跨源)的资源。这是为了应对同源策略(SOP{Same Origin Policy})而设计的。所有常见的Web浏览器都实现了它,并于2014年1月被W3C推荐为标准。简单来说,可以将其看作是一种应对跨源资源的技术。
那么它是如何应对同源策略的呢?
为了理解CORS,我们需要先了解同源策略的必要性。
同源策略(SOP)
同源策略将具有相同组合的方案(协议)、主机和端口视为同源,并把它们作为同样受保护的资源来处理。例如,如果我们有一个URL,比如https://example.com/explain_cors
,那么源就是以下部分:
- 源:https://example.com
- 协议:https
- 主机:example.com
- 端口:80
同源策略是一种安全限制,用于阻止一个网站的JavaScript等客户端脚本访问另一个网站的资源。如果iframe中嵌入的页面可以使用JavaScript进行访问,那么登录信息等敏感信息可能就会被获取。如果嵌入的是自己的网站,那么没有问题,但如果被外部站点随意嵌入并通过JavaScript窃取信息,那就会产生安全问题。为了保证这种安全性,浏览器采用了同源策略。实际上,我们可以通过一些实验来验证浏览器的同源策略是否有效。
例如,从网址:http://localhost:3000 向同一源的http://localhost:3000/api 发送请求。
请求被正常处理。然后,让我们试着向一个不同源的http://site.localhost:3000/api 发送请求。
请求被CORS策略阻止。这证明了同源策略是起作用的。
然而,也有一些场景我们可能需要使用跨源资源。比如,需要为A站点提供一个生成唯一ID的API。
提供ID的API:https://api.example.com
在这种情况下,站点A会执行一段js代码,这段代码会向提供ID的API发送请求。API生成数据后返回给站点A。然而,由于这两个站点的源不同,同源策略就不允许这种请求,这就需要CORS来解决。
CORS 的工作原理
CORS 请求大致分为两种类型。
- 简单请求(Simple Request)
- 预检请求(Prefilight Request)
这两种请求的行为是不同的,为什么会有这么大的区别呢?首先,是浏览器自动决定应该使用哪种类型的请求。浏览器是根据以下原则决定的:如果请求没有符合一些特定的条件,那么就将其作为预检请求处理。
简单的请求
浏览器在以下条件下判定该请求为简单请求: 基本上,这适用于包含令牌等敏感信息的可能性较低的情况。
-
HTTP 方法是GET、HEAD或POST
-
包含的头信息仅为以下几种:
- Accept - Accept-Language - Content-Language - Content-Type (但只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
简单请求的CORS处理方式
即使没有CORS支持,从浏览器到服务器的请求也会正常发送。服务器端的请求处理也是正常的,但由于跨域,浏览器并不返回响应,而是报错。解决这个问题的方法就是在服务器端设置允许来自哪个域的访问。通过设置Access-Control-Allow-Origin
就可以解决这个问题。
如果从站点A:https://example.com
向提供ID的API:https://api.example.com
发送请求,那么服务器端(API)就需要进行如下设置:Access-Control-Allow-Origin: https://api.example.com
这样一来,如果域名匹配,就被认为是正常的响应,浏览器就不会报CORS错误了。
预检请求
如前文所述,如果请求不符合简单请求的特定条件(也就是说,浏览器认为请求存在风险),就会被视为预检请求。在预检请求中,当浏览器向服务器发送请求时,首先要发送一个HTTP Option请求。这个Option请求就是预检请求的特征。在实际的请求之前,浏览器首先发送一个Option请求以获取CORS设置。然后,浏览器根据预检请求的结果来决定是否进行实际的请求。因此,与简单请求不同,预检请求不必担心会执行服务器端的操作。这就是简单请求和预检请求的主要区别。
预检请求的CORS处理方式
要处理预检请求,服务器端需要对Option方法的请求进行响应。
app.options('*', (req, res) => {
res.set('Access-Control-Allow-Origin', '<https://example.com>');
res.set('Access-Control-Allow-Methods', 'GET, POST');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.status(204).end();
});
这样,对于请求,服务器可以返回Option方法的响应,并添加CORS设置。
Access-Control-Allow-Origin
用于指定允许的域名。Access-Control-Allow-Methods
用于指定允许的 HTTP 方法(GET,POST)。Access-Control-Allow-Headers
用于指定请求中可以包含的头部类型。
评论(0)