为什么我的CORS配置没有导致传入请求被过滤?如何使它仅接受来自特定来源的请求?
我希望目前在http://localhost:3000
上运行的仅限Rails 5 API的应用程序仅接受来自NodeJS前端应用程序(现在在http://localhost:8888
上运行)的请求.
I'd like my Rails 5 API-only app, for now running on http://localhost:3000
, to only accept requests from my NodeJS front-end app, for now running on http://localhost:8888
.
所以我这样配置/config/initializers/cors.rb
:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:8888"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
我写了这个测试:
#/spec/request/cors_request_spec.rb
RSpec.feature "CORS protection", type: :request do
it "should accept a request from a whitelisted domain" do
get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "http://localhost:8888"
expect(response.status).to eql(200)
end
it "should reject a request from a non-whitelisted domain" do
get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "https://foreign.domain"
expect(response.status).to eql(406)
end
end
第一个测试通过了预期的测试.但是第二个失败,响应码为200.为什么?
The first test is passing as expected. But the second is failing with a response code of 200. Why?
(顺便说一句,我不是嫁给406响应代码;只有一个表示请求无法实现的代码.)
(I'm not wed to a 406 response code by the way; just one that indicates the request will not be fulfilled.)
CORS配置不会阻止服务器基于Origin
请求标头的值接受请求.您不能仅通过CORS配置来做到这一点.
CORS configuration won’t prevent the server from accepting requests based on the value of the Origin
request header. You can’t do that just through CORS configuration.
在服务器上配置CORS支持时,服务器所做的所有不同操作只是发送Access-Control-Allow-Origin
响应标头和其他CORS响应标头.
When you configure CORS support on a server, all that the server does differently is just to send the Access-Control-Allow-Origin
response header and other CORS response headers.
只有通过浏览器才能实际执行CORS限制.它不是由服务器强制执行的.
Actual enforcement of CORS restrictions is done only by browsers. It’s not enforced by servers.
该协议的工作方式是,无论您在服务器端进行何种CORS配置,服务器都会继续接受来自所有客户端的请求并以其他方式起源(因此,来自所有起源的所有客户端都将继续从)获得响应.服务器,就像他们否则会那样.
The way the protocol works is that regardless of what CORS configuration you make on the server side, the server continues to accept requests from all clients and origins it otherwise would—and so all clients from all origins continue to get responses from the server just as they otherwise would.
因此,即使您在浏览器devtools中看到一个错误,即来自前端JavaScript代码的跨域请求失败,您仍然可以在浏览器devtools中看到响应.
So even when you see an error in your browser devtools that a cross-origin request from your frontend JavaScript code failed, you’ll still be able to see the response in browser devtools.
但是,仅仅因为您的浏览器可以看到响应,并不意味着浏览器会将其公开给您的前端JavaScript代码.如果将请求发送到的服务器选择通过允许该来源的Access-Control-Allow-Origin
标头响应,则浏览器仅将跨域请求的响应公开给在特定来源运行的前端代码.
But just because your browser can see the response doesn’t mean the browser will expose it to your frontend JavaScript code. Browsers only expose responses from cross-origin requests to your frontend code running at a particular origin if the server the request was sent to opts-in to allowing the request by responding with an Access-Control-Allow-Origin
header that allows that origin.
因此,对于任何具有Origin
请求标头与https://foreign.domain
匹配的请求,问题中的配置代码段应导致浏览器在客户端发出一条消息,指出无法加载http://localhost:3000/api/v1/bodies.json
,因为没有
So for any requests with an Origin
request header matching https://foreign.domain
, the configuration snippet in the question should cause browsers to emit a message on the client side saying http://localhost:3000/api/v1/bodies.json
can’t be loaded because there’s no Access-Control-Allow-Origin
response header in the response (because your configuration causes the server to only send that header in responses to your whitelisted origins).
但这就是您可以通过CORS完成的全部工作.您无法仅通过在服务器端进行任何CORS配置来阻止服务器端接受并响应来自特定来源的请求.如果要执行此操作,则需要使用CORS配置以外的其他方法来完成此操作.
But that’s all you can do through CORS. You can’t prevent the server side from accepting and responding to requests from particular origins just by doing any CORS configuration on the server side. If you want to do that, you need to do it using something other than just CORS configuration.