在 python 的请求库中禁用 SSL 证书验证是否安全?
Is it safe to disable SSL certificate verification in pythons's requests lib?
我很清楚,一般来说,事实并非如此。但在我的特殊情况下,我正在编写一个简单的 python 网络抓取程序,它将 运行 作为 cron 作业每小时进行一次,我想确保忽略验证不会有风险通过将 verify
设置为 False
.
的 SSL 证书
P.S。
我决定禁用此功能的原因是因为在尝试发出请求时 response = requests.get('url')
它引发了 SSLError
而我不知道如何处理它。
编辑:
好的,在 sigmavirus24 和其他人的帮助下,我终于设法解决了这个问题。以下是我是如何做到的解释:
- 我 运行 在 https://ssllabs.com/ 进行了测试,根据 SSLLabs 提供的报告,由于 "incomplete certificate chain" 问题(有关如何证书的更多详细信息)验证工作阅读 sigmaviruses24 的回答)。
在我的案例中,其中一位中介人失踪了。
- 我使用 google 搜索了它的指纹并以 .pem 格式下载了它。
然后我用了"certifi"(这是一个python包,用于提供Mozilla的CA Bundle。如果你没有,你可以用[=15=安装它]) 找到根证书(再次通过其指纹)。这可以按如下方式完成:
$ ipython
In [1]: import certifi
In [2]: certifi.where()
Out[2]: /usr/lib/python3.6/site-packages/certifi/cacert.pem
In [3]: quit
$ emacs -nw /usr/lib/python3.6/site-packages/certifi/cacert.pem
或者在 bash 中,您可以发出 $ emacs -nw $(python -m certifi)
打开 cacert.pem 文件。
- 将两个证书合并到一个文件中,然后将其路径提供给验证参数。
另一种(更简单但并非总是可行)的方法是从 SSLLabs 下载整个链,就在 "Additional Certificates (if supplied)" 部分前面有 "Downlaod server chain" 按钮。单击它,将链保存在.pem文件中,并在调用requests的get方法时,将文件路径提供给verify参数。
这可能更适合 https://security.stackexchange.com/。
实际上,它只比使用 HTTP 而不是 HTTPS 略微 好。因此几乎所有(除了没有服务器证书,有人必须主动做某事)HTTP 的风险都适用。
基本上可以看到中间人攻击发送和接收的数据.. 或者即使该站点 曾经 被破坏并且证书是从他们那里偷来的。如果您正在为该站点存储 cookie,那么这些 cookie 将被泄露(即,如果 facebook.com 那么会话令牌可能会被盗)如果您使用用户名和密码登录,那么它们也可能被盗。
检索到这些数据后,您会如何处理这些数据?你在下载任何可执行代码吗?您正在下载某些东西(存储在 web-server 上的图像吗?),而熟练的攻击者(甚至通过修改路由器上的 DNS 设置)可能会强制您下载文件 ("news.php") 并且存储在您的 web-server 上,可以执行(一个 .php 脚本而不是 web-page)?
来自文档:
Requests can also ignore verifying the SSL certficate if you set verify to False.
requests.get('https://kennethreitz.com', verify=False)
如果您没有在请求中使用敏感信息,则为 'safe'。
你不能在 HTML 本身中植入病毒(据我所知),Javascript 可能是一个漏洞,所以 Python 不是一件好事不处理它。
所以总而言之,你应该是安全的
这里的正确答案是"it depends"。
你给我们提供的信息很少,所以我将做一些假设并在下面列出它们(如果有任何不匹配,那么你应该重新考虑你的选择):
- 您在 CRON 作业中不断连接到同一个网站
- 您相当了解该网站并且确定 certificate-related 错误是良性的
- 您没有向网站发送敏感数据以抓取它(例如登录名和用户名)
如果是这种情况(我猜是这样),那么它通常应该是无害的。也就是说,它是否是 "safe" 取决于您在两台计算机通过 Internet 相互通信的上下文中对该词的定义。
正如其他人所说,Requests 不会尝试呈现 HTML、解析 XML 或执行 JavaScript。因为它只是在检索您的数据,所以您 运行 最大的风险是没有从您认为数据来自的服务器接收到可以验证的数据。但是,如果您将请求与执行上述操作的内容结合使用,则中间的恶意人员可以对您进行无数 潜在 攻击。
还有一些选项意味着您不必放弃验证。例如,如果服务器使用 self-signed 证书,您可以获取 PEM 格式的证书,将其保存到文件中,并将该文件的路径提供给 verify
参数。然后请求将能够为您验证证书。
所以,正如我所说,这取决于。
根据 Albert 的回复更新
所以似乎正在发生的事情是,有问题的网站只发送有效的叶证书。该网站依赖于当前工作方式如下的浏览器行为:
浏览器连接到网站并注意到该网站没有发送完整的证书链。然后它去检索中介,验证它们,并完成连接。但是,请求使用 OpenSSL 进行验证,而 OpenSSL 不包含任何此类行为。由于验证逻辑几乎完全在 OpenSSL 中,因此在这种情况下 Requests 无法模拟浏览器。
此外,安全工具(例如 SSLLabs)已开始根据网站的安全排名计算此配置。越来越多的人认为网站应该发送整个链条。如果您遇到一个没有的网站,联系他们并告知他们这是最好的前进方向。
如果网站拒绝更新他们的证书链,那么 Requests 的用户可以检索 PEM 编码的中间证书并将它们粘贴在 .pem
文件中,然后他们将其提供给 verify
参数。 Requests 目前仅在其信任库中包含 Root 证书(就像每个浏览器一样)。它永远不会发送中间证书,因为中间证书太多了。因此,将中介机构与根证书捆绑在一起将使您能够验证网站的证书。 OpenSSL 将有一个 PEM 编码文件,每个 link 都在链中,并且能够验证到根证书。
我很清楚,一般来说,事实并非如此。但在我的特殊情况下,我正在编写一个简单的 python 网络抓取程序,它将 运行 作为 cron 作业每小时进行一次,我想确保忽略验证不会有风险通过将 verify
设置为 False
.
P.S。
我决定禁用此功能的原因是因为在尝试发出请求时 response = requests.get('url')
它引发了 SSLError
而我不知道如何处理它。
编辑:
好的,在 sigmavirus24 和其他人的帮助下,我终于设法解决了这个问题。以下是我是如何做到的解释:
- 我 运行 在 https://ssllabs.com/ 进行了测试,根据 SSLLabs 提供的报告,由于 "incomplete certificate chain" 问题(有关如何证书的更多详细信息)验证工作阅读 sigmaviruses24 的回答)。
在我的案例中,其中一位中介人失踪了。
- 我使用 google 搜索了它的指纹并以 .pem 格式下载了它。
然后我用了"certifi"(这是一个python包,用于提供Mozilla的CA Bundle。如果你没有,你可以用[=15=安装它]) 找到根证书(再次通过其指纹)。这可以按如下方式完成:
$ ipython In [1]: import certifi In [2]: certifi.where() Out[2]: /usr/lib/python3.6/site-packages/certifi/cacert.pem In [3]: quit $ emacs -nw /usr/lib/python3.6/site-packages/certifi/cacert.pem
或者在 bash 中,您可以发出 $ emacs -nw $(python -m certifi)
打开 cacert.pem 文件。
- 将两个证书合并到一个文件中,然后将其路径提供给验证参数。
另一种(更简单但并非总是可行)的方法是从 SSLLabs 下载整个链,就在 "Additional Certificates (if supplied)" 部分前面有 "Downlaod server chain" 按钮。单击它,将链保存在.pem文件中,并在调用requests的get方法时,将文件路径提供给verify参数。
这可能更适合 https://security.stackexchange.com/。
实际上,它只比使用 HTTP 而不是 HTTPS 略微 好。因此几乎所有(除了没有服务器证书,有人必须主动做某事)HTTP 的风险都适用。
基本上可以看到中间人攻击发送和接收的数据.. 或者即使该站点 曾经 被破坏并且证书是从他们那里偷来的。如果您正在为该站点存储 cookie,那么这些 cookie 将被泄露(即,如果 facebook.com 那么会话令牌可能会被盗)如果您使用用户名和密码登录,那么它们也可能被盗。
检索到这些数据后,您会如何处理这些数据?你在下载任何可执行代码吗?您正在下载某些东西(存储在 web-server 上的图像吗?),而熟练的攻击者(甚至通过修改路由器上的 DNS 设置)可能会强制您下载文件 ("news.php") 并且存储在您的 web-server 上,可以执行(一个 .php 脚本而不是 web-page)?
来自文档:
Requests can also ignore verifying the SSL certficate if you set verify to False.
requests.get('https://kennethreitz.com', verify=False)
如果您没有在请求中使用敏感信息,则为 'safe'。
你不能在 HTML 本身中植入病毒(据我所知),Javascript 可能是一个漏洞,所以 Python 不是一件好事不处理它。
所以总而言之,你应该是安全的
这里的正确答案是"it depends"。
你给我们提供的信息很少,所以我将做一些假设并在下面列出它们(如果有任何不匹配,那么你应该重新考虑你的选择):
- 您在 CRON 作业中不断连接到同一个网站
- 您相当了解该网站并且确定 certificate-related 错误是良性的
- 您没有向网站发送敏感数据以抓取它(例如登录名和用户名)
如果是这种情况(我猜是这样),那么它通常应该是无害的。也就是说,它是否是 "safe" 取决于您在两台计算机通过 Internet 相互通信的上下文中对该词的定义。
正如其他人所说,Requests 不会尝试呈现 HTML、解析 XML 或执行 JavaScript。因为它只是在检索您的数据,所以您 运行 最大的风险是没有从您认为数据来自的服务器接收到可以验证的数据。但是,如果您将请求与执行上述操作的内容结合使用,则中间的恶意人员可以对您进行无数 潜在 攻击。
还有一些选项意味着您不必放弃验证。例如,如果服务器使用 self-signed 证书,您可以获取 PEM 格式的证书,将其保存到文件中,并将该文件的路径提供给 verify
参数。然后请求将能够为您验证证书。
所以,正如我所说,这取决于。
根据 Albert 的回复更新
所以似乎正在发生的事情是,有问题的网站只发送有效的叶证书。该网站依赖于当前工作方式如下的浏览器行为:
浏览器连接到网站并注意到该网站没有发送完整的证书链。然后它去检索中介,验证它们,并完成连接。但是,请求使用 OpenSSL 进行验证,而 OpenSSL 不包含任何此类行为。由于验证逻辑几乎完全在 OpenSSL 中,因此在这种情况下 Requests 无法模拟浏览器。
此外,安全工具(例如 SSLLabs)已开始根据网站的安全排名计算此配置。越来越多的人认为网站应该发送整个链条。如果您遇到一个没有的网站,联系他们并告知他们这是最好的前进方向。
如果网站拒绝更新他们的证书链,那么 Requests 的用户可以检索 PEM 编码的中间证书并将它们粘贴在 .pem
文件中,然后他们将其提供给 verify
参数。 Requests 目前仅在其信任库中包含 Root 证书(就像每个浏览器一样)。它永远不会发送中间证书,因为中间证书太多了。因此,将中介机构与根证书捆绑在一起将使您能够验证网站的证书。 OpenSSL 将有一个 PEM 编码文件,每个 link 都在链中,并且能够验证到根证书。