为啥我的 CORS 配置没有导致服务器过滤传入的请求?如何让服务器只接受来自特定来源的请求?

Posted

技术标签:

【中文标题】为啥我的 CORS 配置没有导致服务器过滤传入的请求?如何让服务器只接受来自特定来源的请求?【英文标题】:Why isn't my CORS configuration causing the server to filter incoming requests? How can I make the server only accept requests from a specific origin?为什么我的 CORS 配置没有导致服务器过滤传入的请求?如何让服务器只接受来自特定来源的请求? 【发布时间】:2017-10-17 12:13:43 【问题描述】:

我希望我的 Rails 5 API-only 应用程序,目前在 http://localhost:3000 上运行,只接受来自我的 NodeJS 前端应用程序的请求,现在在 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。为什么?

(顺便说一句,我不喜欢 406 响应代码;只是一个表明请求不会被满足的代码。)

【问题讨论】:

你是怎么做到的? 【参考方案1】:

CORS 配置不会阻止服务器根据 Origin 请求标头的值接受请求。你不能仅仅通过 CORS 配置来做到这一点。

当您在服务器上配置 CORS 支持时,服务器所做的所有不同只是发送 Access-Control-Allow-Origin 响应标头和其他 CORS 响应标头。

CORS 限制的实际执行仅由浏览器完成。它不是由服务器强制执行的。

该协议的工作方式是,无论您在服务器端进行何种 CORS 配置,服务器都会继续接受来自所有客户端和来源的请求,否则它会继续接受来自所有来源的所有客户端的响应。服务器,就像他们原本会做的那样。

因此,即使您在浏览器开发工具中看到来自前端 javascript 代码的跨域请求失败的错误,您仍然可以在浏览器开发工具中看到响应。

但仅仅因为您的浏览器可以看到响应并不意味着浏览器会将其暴露给您的前端 JavaScript 代码。如果将请求发送到的服务器通过使用允许该来源的Access-Control-Allow-Origin 标头响应来选择允许该请求,浏览器只会将来自跨域请求的响应暴露给在特定来源运行的前端代码。

所以对于任何带有与https://foreign.domain 匹配的Origin 请求标头的请求,问题中的配置sn-p 应该会导致浏览器在客户端发出一条消息说http://localhost:3000/api/v1/bodies.json 无法加载,因为没有Access-Control-Allow-Origin 响应中的响应标头(因为您的配置导致服务器仅发送该标头以响应您的白名单来源)。

但这就是您通过 CORS 所能做的一切。您不能仅通过在服务器端进行任何 CORS 配置来阻止服务器端接受和响应来自特定来源的请求。如果你想这样做,你需要使用除 CORS 之外的其他东西。

【讨论】:

以上是关于为啥我的 CORS 配置没有导致服务器过滤传入的请求?如何让服务器只接受来自特定来源的请求?的主要内容,如果未能解决你的问题,请参考以下文章

我的请求是跨源请求吗?(heroku 上的 Django rest api,CORS 没有阻止我的请求)

为啥 Flask-Cors 在生产中没有检测到我的跨域域?

为啥 Spring Security 身份验证会导致 CORS 错误

为啥我在 Spring Boot 中从服务器端配置并做出反应时出现 CORS 错误?

为啥 CORS 适用于 API 请求,但不适用于我的 Nginx 配置中的媒体文件(例如 mp4、webm)?

spring security CORS 过滤器允许没有“Origin”标头的请求