使用 Flask、gunicorn、gevent 绕过 SSL 证书验证

问题描述

我收到 CERTIFICATE_VERIFY_Failed 错误,因为当我使用 urllib 发出 openurl 请求时,它正在检查 https 证书,并且由于我的端点使用的是自签名证书(使用我们公司的内部 CA),它们显然未通过验证检查.

我知道我可以使用请求,或创建我自己的上下文,但是调用的是第三方库,我无法改变这种情况发生的方式。由于它只是一个内部应用程序,我不太关心验证,所以我很高兴跳过对所有 https 请求的验证。

互联网建议最简单的方法是创建一个环境变量PYTHONHTTPsveRIFY=0,或者使用

猴子修补ssl库
# Set prior to pretty much everything

import ssl
if hasattr(ssl,'_create_unverified_context'):
    ssl._create_default_https_context = ssl._create_unverified_context

所以这一切正常,直到我使用配置为使用 gevent worker 的 gunicorn 运行。我也被困在使用 python 2.7.18

想知道是否有人有任何解决方案或想法?

解决方法

所以经过一番头痛之后,我解决了这个问题,因为当 gunicorn 启动 gevent 工作程序时,他们会在我的应用程序初始化后调用 gevent.monkey.patch_all()。不幸的是,这会覆盖我的猴子补丁(在我的应用程序初始化中完成)并重置。

我认为这应该仍然可以,因为 PYTHONHTTPSVERIFY=0 仍然设置,并且 SSL 库应该看到这一点,并忽略验证。然而! gevent 替换(猴子补丁)系统的 SSL 库是旧版本,它不查找 ENV 变量。

所以,我需要一种在 gevent 猴子补丁之后进一步对猴子补丁 (ssl._create_default_https_context = ssl._create_unverified_context) 的方法!

幸运的是,gunicorn 提供了一个钩子来做到这一点,我们可以在配置文件中设置一个函数来为我们做这件事。我的 gunicorn 配置看起来像这样:

bind = '0.0.0.0:8080'
accesslog = 'gunicornaccess.log'
errorlog = 'gunicornerror.log'
loglevel = 'DEBUG'
timeout = 240000
pidfile = 'gunicorn.pid'
debug = True
worker_class = 'gevent'
workers = 8
threads = 4

def post_worker_init(worker):
   import ssl
   ssl._create_default_https_context = ssl._create_unverified_context

我的意思是猴子补丁一般来说是个坏主意,但这是我让它工作的唯一方法。希望这能让其他人免于我到达这里时遇到的麻烦。