Python Flask CORS - API 始终允许任何来源

Python Flask CORS - API always allows any origin

我看了很多 SO 答案,似乎找不到这个问题。我觉得我只是遗漏了一些明显的东西。

我有一个基本的 Flask api,我已经实现了 flask_cors 扩展和自定义 Flask 装饰器 [@crossdomain from Armin Ronacher].1 (http://flask.pocoo.org/snippets/56/)两者都显示相同的问题。

这是我的示例应用程序:

application = Flask(__name__,
            static_url_path='',
            static_folder='static')
CORS(application)
application.config['CORS_HEADERS'] = 'Content-Type'

@application.route('/api/v1.0/example')
@cross_origin(origins=['http://example.com'])
# @crossdomain(origin='http://example.com')
def api_example():
  print(request.headers)
  response = jsonify({'key': 'value'})
  print(response.headers)
  return response

(插入编辑 3):

当我在浏览器中从 JS 向该端点发出 GET 请求时(从 127.0.0.1),它总是 returns 200,而我希望看到:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:5000' is therefore not allowed access. The response had HTTP status code 403.

CURL:

ACCT:ENVIRON user$ curl -i http://127.0.0.1:5000/api/v1.0/example
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 20
Access-Control-Allow-Origin: http://example.com
Server: Werkzeug/0.11.4 Python/2.7.11
Date: [datetime]

{
  "key": "value"
}

日志:

Content-Length: 
User-Agent: curl/7.54.0
Host: 127.0.0.1:5000
Accept: */*
Content-Type: 


Content-Type: application/json
Content-Length: 20


127.0.0.1 - - [datetime] "GET /api/v1.0/example HTTP/1.1" 200 -

我什至没有在响应中看到所有正确的 headers,而且它似乎并不关心请求中的来源。

知道我遗漏了什么吗?谢谢!


编辑:

作为旁注,查看文档示例 here (https://flask-cors.readthedocs.io/en/v1.7.4/#a-more-complicated-example),它显示:

@app.route("/")
def helloWorld():
    '''
        Since the path '/' does not match the regular expression r'/api/*',
        this route does not have CORS headers set.
    '''
    return '''This view is not exposed over CORS.'''

...这很有趣,因为我已经在没有任何 CORS 装饰的情况下公开了根路径(和其他路径),并且它们从任何来源都可以正常工作。因此,此设置似乎存在根本性错误。

按照这些思路,教程 here (https://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask) 似乎表明 Flask apis 自然应该在没有保护的情况下公开(我认为那只是因为尚未应用 CORS 扩展) ,但我的应用程序基本上就像 CORS 扩展根本不存在一样运行(除了您可以在日志中看到的一些注释)。


编辑 2:

我的评论不清楚,所以我在 AWS API 网关上创建了三个具有不同 CORS 设置的示例端点。它们是简单地 return "success":

的 GET 方法端点

1) CORS 未启用(默认):

回复:

XMLHttpRequest cannot load https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-default. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:5000' is therefore not allowed access. The response had HTTP status code 403.

2) 启用 CORS - 来源受限:

回复:

XMLHttpRequest cannot load https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-example. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://example.com' that is not equal to the supplied origin. Origin 'http://127.0.0.1:5000' is therefore not allowed access.

3) 启用 CORS - 来源通配符:

回复:

"success"

我在基础架构方面经验不足,但我的预期是启用 Flask CORS 扩展会导致我的 api 端点模仿此行为,具体取决于我在 origins= 设置中的设置.我在这个 Flask 设置中缺少什么?


解决方案编辑:

好吧,考虑到我这边的某些东西显然不正常,我剥离了我的应用程序和 re-implemented 一些非常基本的 APIs,用于 CORS 来源限制的每个变体。我一直在使用 AWS 的 elastic beanstalk 来托管测试环境,所以我 re-uploaded 这些示例和 运行 对每个示例的 JS ajax 请求。它现在正在工作。

我在裸端点上收到 Access-Control-Allow-Origin 错误。看来,当我为部署配置应用程序时,我取消了注释 CORS(application, resources=r'/api/*'),这显然允许裸端点的所有来源!

我不确定为什么我的具有特定限制的路线 (origins=[]) 也允许所有内容,但这一定是某种类型的拼写错误或一些小问题,因为它现在正在运行。

特别感谢 sideshowbarker 的所有帮助!

根据您的问题 as-is,您并不完全清楚您期望的行为是什么。但就 CORS 协议的工作方式而言,您的服务器似乎已经按预期运行。

具体来说,问题中引用的 curl 回复显示了此回复 header:

Access-Control-Allow-Origin: http://example.com

这表明服务器已经配置为告诉浏览器,只允许来自前端 JavaScript 代码 运行 的 cross-origin 请求,如果代码是 运行在原点 http://example.com.

如果您期望的行为是服务器现在将拒绝来自 non-browser 客户端(例如 curl)的请求,那么 CORS 配置本身不会导致服务器这样做。

当您配置 CORS 支持时,服务器唯一不同的是发送 Access-Control-Allow-Origin 响应 header 和其他 CORS 响应 header。就是这样。

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

因此,无论您进行何种 server-side CORS 配置,服务器仍会继续接受来自所有客户端和来源的请求;换句话说,来自所有来源的所有客户端仍然继续从服务器获得响应,就像它们在其他情况下一样。

但是 浏览器 只会将来自 cross-origin 请求的响应公开到特定来源的前端 JavsScript 代码 运行 如果服务器将请求发送到 opts-in 允许请求,通过响应 Access-Control-Allow-Origin header 允许该来源。

这是您使用 CORS 配置唯一可以做的事情。您不能仅通过进行任何 server-side CORS 配置就使服务器仅接受和响应来自特定来源的请求。为此,您需要使用除 CORS 配置之外的其他东西。