preflight OPTIONS 检查给出 403 和 Access-Control-Allow-Origin ”*”

Posted

技术标签:

【中文标题】preflight OPTIONS 检查给出 403 和 Access-Control-Allow-Origin ”*”【英文标题】:preflight OPTIONS check gives 403 with Access-Control-Allow-Origin ”*” 【发布时间】:2018-10-15 10:41:04 【问题描述】:

我在一个子域上提供了一个单页应用程序,在另一个子域上提供了一个 api。我在飞行前检查到 api 的 XHR POST 时收到 403 Forbidden。

在 curl 中调试它显示:

 curl  -H "Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
 -H "Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type" \
-X OPTIONS --verbose http://backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com/api/users
*   Trying 54.153.79.158...
* TCP_NODELAY set
* Connected to backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com (54.153.79.158) port 80 (#0)
> OPTIONS /api/users HTTP/1.1
> Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> User-Agent: curl/7.54.0
> Accept: */*
> Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: content-type
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 403 Forbidden
< Date: Fri, 04 May 2018 21:16:52 GMT
< Server: Apache/2.4.27 (Red Hat) OpenSSL/1.0.1e-fips
< Cache-Control: no-cache, private
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: accept, access-control-allow-origin, content-type
< Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
< Content-Length: 18
< Content-Type: text/html; charset=UTF-8
< Set-Cookie: 45fe47f0bb613513b8e98d0599b628f9=dd4b5c95b51d6168419458748b392421; path=/; HttpOnly
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
< 
* Connection #0 to host backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com left intact
Origin not allowed

然而响应中的Access-Control-Allow-Origin: * 表明它应该允许Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com 命名请求。

如果我从请求中删除 Origin 标头,我会得到 200。

我尝试在服务器上显式设置 Access-Control-Allow-Origin 以匹配请求的 Origin,但这也会返回 403:

 curl  -H "Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
 -H "Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type" \
-X OPTIONS --verbose http://backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com/api/users
*   Trying 54.153.79.158...
* TCP_NODELAY set
* Connected to backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com (54.153.79.158) port 80 (#0)
> OPTIONS /api/users HTTP/1.1
> Host: backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> User-Agent: curl/7.54.0
> Accept: */*
> Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: content-type
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 403 Forbidden
< Date: Fri, 04 May 2018 21:32:52 GMT
< Server: Apache/2.4.27 (Red Hat) OpenSSL/1.0.1e-fips
< Cache-Control: no-cache, private
< Access-Control-Allow-Origin: http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com
< Access-Control-Allow-Headers: accept, access-control-allow-origin, content-type
< Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
< Content-Length: 18
< Content-Type: text/html; charset=UTF-8
< Set-Cookie: 45fe47f0bb613513b8e98d0599b628f9=a913ecc9ded73c3ac76fbb38d93e15a7; path=/; HttpOnly
* HTTP/1.0 connection set to keep alive!
< Connection: keep-alive
< 
* Connection #0 to host backend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com left intact
Origin not allowed

在服务器上,.htaccess 具有以下配置:

<IfModule mod_headers.c>
    Header add Access-Control-Allow-Origin "http://frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com"
    Header add Access-Control-Allow-Headers "accept, access-control-allow-origin, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>

Access-Control-Allow-Origin 设置为"*" 并不能解决问题。

为什么在似乎允许来源时响应 403 被禁止,我该如何解决?

谢谢!

更新

这是我最新的.htaccess,用于 laravel php 后端:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %HTTP:Authorization .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%HTTP:Authorization]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %REQUEST_FILENAME !-d
    RewriteCond %REQUEST_URI (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %REQUEST_FILENAME !-d
    RewriteCond %REQUEST_FILENAME !-f
    RewriteRule ^ index.php [L]
</IfModule>
<IfModule mod_headers.c>
    Header add Access-Control-Allow-Origin "*"
    Header add Access-Control-Allow-Headers "*"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
</IfModule>

【问题讨论】:

为什么要向 OPTIONS 请求返回 Set-Cookie 响应标头?这可能是相关的......我从未见过像Origin not allowed这样的错误消息...... 设置 cookie 的 api 代码是在负载均衡器后面运行的第 3 方 Laravel 代码。它可能会在每个响应上设置一个 cookie 以获取亲和力。正如我在问题中所说,如果我不设置 origin 标头,它会返回 200。这并不意味着 cookie 是个问题。我发布到的 URL 来自“注册”页面,用于注册用户。因此,如果没有原始标头,它将为 200,这一事实让我认为这是一个 CORS 问题。为什么 cookie 会干扰? 嗯。我怀疑后端代码中的其他地方不允许来源。要么 all 来源被禁止(即 Origin 标头被禁止),要么只允许指定的一组来源,而你的来源不是其中之一。我会检查第 3 方 Laravel 代码。 【参考方案1】:

正如@roryhewitt 在对该问题的评论中所建议的那样,这不是 apache .htaccess 问题。问题是后端 API laravel 应用程序向任何 CORS 请求提供 403。

我删除了mod_headers.c 配置,并使用环境变量CORS_ALLOWED_ORIGINS=frontend-sjm-staging.a3c1.starter-us-west-1.openshiftapps.com 配置了后端应用程序使用的barryvdh/laravel-cors 模块。这将设置allowedOrigins,如here 所示。

【讨论】:

以上是关于preflight OPTIONS 检查给出 403 和 Access-Control-Allow-Origin ”*”的主要内容,如果未能解决你的问题,请参考以下文章

Preflight(options) 请求的正确成功状态代码是啥? [复制]

AngularJS 的 Preflight OPTIONS 请求不适用于 Chrome?

已解决 - CORS、OPTIONS 和 PreFlight 问题 在 Vue.js 中使用 Axios 使用 REST API

401 响应 CORS preflight OPTIONS 请求到 Spring Boot 服务器

CORS preflight OPTIONS 请求从 Windows Authenticated web api 返回 401(未授权)

Angular 6 - Spring MVC :: Options preflight request throws 500 internal Server Error