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

Posted

技术标签:

【中文标题】Python Flask CORS - API 始终允许任何来源【英文标题】:Python Flask CORS - API always allows any origin 【发布时间】:2018-01-14 05:41:23 【问题描述】:

我查看了许多 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):

当我在浏览器中(从 127.0.0.1)从 JS 向该端点发出 GET 请求时,它总是返回 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.

卷曲:

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 -

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

任何想法我错过了什么?谢谢!


编辑:

作为旁注,查看文档示例 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 api 应该自然暴露而无需保护(我认为这只是因为尚未应用 CORS 扩展),但我的应用程序是基本上只是像 CORS 扩展一样操作甚至不存在(除了您可以看到的日志中的一些注释)。


编辑 2:

我的 cmets 不清楚,因此我在 AWS API Gateway 上使用不同的 CORS 设置创建了三个示例端点。它们是简单地返回“成功”的 GET 方法端点:

1) CORS 未启用(默认):

端点:https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-default

回复:

XMLHttpRequest 无法加载 https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-default。 对预检请求的响应未通过访问控制检查:否 请求中存在“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://127.0.0.1:5000” 使用权。响应的 HTTP 状态代码为 403。

2) 启用 CORS - 来源受限:

Access-Control-Allow-Headers:'Content-Type'

访问控制允许来源:'http://example.com'

端点:https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-example

回复:

XMLHttpRequest 无法加载 https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-example。 对预检请求的响应未通过访问控制检查: “Access-Control-Allow-Origin”标头的值为“http://example.com” 这不等于提供的来源。起源 'http://127.0.0.1:5000' 因此不允许访问。

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

访问控制允许标头:“内容类型” 访问控制允许来源:'*' 端点:https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-wildcard

回复:

"success"

我对基础架构没有那么丰富的经验,但我的期望是启用 Flask CORS 扩展会导致我的 api 端点模仿这种行为,具体取决于我在 origins= 设置中设置的内容。我在这个 Flask 设置中缺少什么?


解决方案编辑:

好的,鉴于我这边的某些事情显然不正常,我剥离了我的应用程序,并针对 CORS 来源限制的每个变体重新实现了一些非常基本的 API。我一直在使用 AWS 的弹性 beanstalk 来托管测试环境,所以我重新上传了这些示例并对每个示例运行 JS ajax 请求。它现在正在工作。

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

我不确定为什么我的特定限制 (origins=[]) 的路线也允许一切,但这一定是某种类型的拼写错误或一些小东西,因为它现在可以工作了。

特别感谢 sideshowbarker 的所有帮助!

【问题讨论】:

抱歉,我仍然不清楚您的期望。在我看来,Edit 2 中的所有这些案例都在按预期工作。案例 #1 也是您会考虑按预期工作的案例,对吗?在那一个中​​,您没有为该端点启用 CORS,因此浏览器不允许访问响应。就 CORS 协议而言,案例 #2 也按预期工作,因为您已将允许的来源设置为 http://example.com,但您正在从 http://127.0.0.1:5000 发送请求,因此浏览器不会让您的代码在 @ 运行987654351@查看回复 就 CORS 协议而言,案例 #3 也按预期工作 - 因为您所说的配置是“允许在任何来源运行的前端代码访问来自此端点的响应”,所以在您发送请求的源站运行的代码成功访问响应。 我不明白 “导致我的 api 端点根据我在 origins= 设置中设置的内容来模仿这种行为” 是什么意思 我的 Flask 端点的工作方式与案例 #3 一样,无论是否使用了 CORS 扩展,或者我在装饰器中使用“origins=”包含的任何内容。他们从来没有像案例#1 和#2 那样给我答复。期望 Flask 应用程序像这些示例一样响应,我错了吗? 我应该澄清一下,因为我认为我的问题发生了两种不同的事情,我让这很混乱。 Sideshowbarker,您是正确的,服务器不会阻止任何内容,如 curl 响应所示。那是我的误解。但是,我在浏览器中的 JS 中运行了相同的端点,它的行为也不像案例 #1(如果我不使用 CORS)或案例 #2(如果我使用带有以下内容的装饰器:“@cross_origin(origins =['example.com'])")。所以即使我最初的问题令人困惑,它的行为仍然很奇怪。我将编辑那个 curl 部分,因为那是一个不好的例子。 【参考方案1】:

从您的问题来看,您所期望的行为并不完全清楚。但就 CORS 协议的工作方式而言,您的服务器似乎已经按预期运行。

具体来说,问题中引用的curl 响应显示了此响应标头:

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

这表示服务器已经配置为告诉浏览器,如果代码在源http://example.com 上运行,则仅允许来自浏览器中运行的前端 javascript 代码的跨源请求。

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

当您使用 CORS 支持配置服务器时,唯一的不同之处在于发送 Access-Control-Allow-Origin 响应标头和其他 CORS 响应标头。就是这样。

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

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

浏览器只会将来自跨域请求的响应暴露给在特定来源运行的前端 JavsScript 代码,前提是请求被发送到的服务器选择通过使用 @ 响应来允许请求987654327@ 允许该来源的标头。

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

【讨论】:

感谢您对此的帮助。也许我可以用一个例子来解释。我在 AWS 上设置了一个 API Gateway 端点并尝试在不启用 CORS 的情况下访问它。它返回此响应:“请求的资源上不存在'Access-Control-Allow-Origin'标头。因此,不允许访问源'another-example.com'。”我基本上是在尝试让我的 Flask 应用程序在应用程序中未启用 CORS 时发送该响应,但它始终允许任何访问,即使来自浏览器中 js 的 ajax 请求也是如此。我以为我了解 CORS,但可能缺少服务器设置? 简单来说,我的应用程序似乎根本没有同源策略。我对基础设施不是很有经验,但我认为这是默认启用的。到目前为止,Google 搜索在启用此政策方面没有太大帮助。 我上面的 cmets 具有误导性/不清楚,因此我在问题的“EDIT 2”下添加了其他信息。再次感谢您的帮助。 至于 “试图让我的 Flask 应用程序在应用程序中未启用 CORS 时发送该响应,但它始终允许任何访问,即使来自 js 中的 ajax 请求浏览器” 添加到问题中的示例并不表示“它始终允许任何访问,即使来自浏览器中 js 的 ajax 请求也是如此”——相反,它们表明 浏览器 正在阻塞根据服务器发送的 Access-Control-Allow-Origin 标头按预期访问响应。您是否仍然期望服务器本身进行某种阻塞?服务器本身从不做任何阻塞,永远 EDIT 2 的示例并非来自我的 Flask 应用程序。它们是 AWS API Gateway 上的示例终端节点。是的,它们是我所期望的,但我的 Flask 应用程序的行为方式不同

以上是关于Python Flask CORS - API 始终允许任何来源的主要内容,如果未能解决你的问题,请参考以下文章

Flask-Restful 中的中止方法忽略 CORS 选项

在 Flask 中允许 CORS

Python Flask CORS - 请求的资源上不存在“Access-Control-Allow-Origin”标头

如何使用 Flask-Restless 启用 CORS

JavaScript fetch API和Python Flask头问题

如何使用 flask-cors 库修复 python flask cors 问题