Requests: TLS SNI 支持

创建于 2012-08-01  ·  46评论  ·  资料来源: psf/requests

似乎我在使用需要 TLS SNI 支持的服务器的请求时遇到了问题。 请求什么时候有这个功能? 这是计划好的事情吗?

谢谢,
- 内存

最有用的评论

这在requests/packages/urllib3/contrib/pyopenssl.py 中指定

  • pyOpenSSL(使用 0.13 测试)
  • ndg-httpsclient(使用 0.3.2 测试)
  • pyasn1(使用 0.1.6 测试)

(或 python3.2 或更高版本,始终有效)

所有46条评论

在 stdlib 的 ssl 模块之上的 Python 2.x 中不可能。

Twisted 有吧? 也许是时候依赖 pyopenssl 或其他一些 ssl 模块了?

有一个 urllib3 拉取请求,为 Py32+ 添加了 SN​​I 支持,但仍需要测试覆盖。 https://github.com/shazow/urllib3/pull/89

shzow:谢谢指点。 不幸的是,我正在使用 Twisted/Flask,这意味着我只能使用 2.7。 Twisted 似乎可以做这样的事情,但我还没有看到例子,它需要 pyopenssl + twisted 解码才能做到这一点。 我不是这方面的专家。 在这一点上,只想包装一些像 wget 这样的命令行实用程序... :(

PyOpenSSL 应该能够在 2.x 上做到这一点。 所以有希望。

我可以让它与 pyopenssl 一起工作。 但是我仍然很难正确地完成它。 http://pbin.be/show/719/ - 一种作品。 但是,必须在其上构建 API 才能发挥作用。 我仍然无法弄清楚如何将正确的上下文传递给代理。

卢卡萨:这解决了吗?

不可以。我们在 shazow/urllib3#89 上被屏蔽了。

合并。 继续。 :)

请注意,它目前仅在 Py32+ 上受支持。 不过应该足够开始了。

另一个公平的警告:现在在 urllib3 master 上对 Py32 的一些测试失败了。 将不胜感激解决此问题的一些帮助(并可能影响此功能): https :

在 py26、py27、py32、py33 上的 archlinux x64 上对我有用

啊,我应该有资格说这是在 OSX 上。 人渣 OSX。

t-8ch:sni 测试是否通过了 py26/27/32 和 33?

SNI 测试甚至不在 py2 上运行,但在 py32 和 py33 上它可以工作。
py32之前没有办法用标准库的ssl模块做SNI。

@shazow :想必您对让 urllib3 依赖于 PyOpenSSL 没有兴趣?

我很高兴有一个单独的库,它通过 PyOpenSSL 支持将 SSL 添加到 urllib3。

看起来@t-8ch 正在通过 urllib3 的工作将它淘汰出局。 我会让他告诉我们什么时候可以关闭。

urllib3 对带有 python2 的 SNI 有可选的支持,但有一些可选的依赖项。 (见urllib3#156 )。

我相信这应该使用:

from requests.packages.urllib3.contrib import pyopenssl
pyopenssl.inject_into_urllib3

将此添加到packages中的setup.py

requests.packages.urllib3.contrib

请注意,默认情况下不导入contrib包。

在请求中启用 SNI 基本上有两种选择:

  • 创建函数以手动启用基本上运行上述代码的 SNI。 (缺点是用户需要明确启用 SNI 支持)。
  • 尝试导入先决条件。 如果它们存在,请启用 SNI,否则不要。

我在实现这两种选择中的任何一种都没有问题,但我更想知道哪个是请求的首选。 我个人投票支持第二种选择。

顺便说一句:既然我们得到了 urllib3 的支持,我们可以重新打开这个问题吗?

我实际上更喜欢前者,因为需要它的人知道他们会需要它,而且人数少到不会引起太多抱怨。 但是,如果我们要与现有 API 保持一致,则后者将是实现它的方式。 目前,urllib3(和请求)将提供 API 以在没有 ssl 模块的情况下发送 HTTPS 请求,但在 ssl 模块不可用的情况下将失败。 换句话说,API 就在那里,您可以使用它,但它无法工作,并且由异常指示。

至于重新打开这个,这取决于@kennethreitz。 当然,问题(所有这些)是我们目前处于功能冻结状态(#1165、#1168),所以我不确定这项工作是否值得做,因为它可能不被接受。

让我更清楚一点:我的第二个选择的意思是“如果可选的 deps 可用,请尝试使用 SNI,但仍然使用 SSL,因为我们总是拥有它,但它们不是。”。 这不应该破坏到目前为止存在的任何东西。

至于重新(或不)这个问题,恕我直言,这个问题不应该掉以轻心。 在许多情况下,如果没有 SNI 支持,请求可能会变得无用。 特别是,在没有 SNI 的情况下,单个 IPv4 主机上的多个域变得不可能。 对于许多用户来说,额外的 IPv4 地址是不可能的(由于它们的成本)。

无论如何,这是一半功能,一半错误,尽管我会等待@kennethreitz关于重新打开问题的回复。

Hugo:我只是做了 pip install -U 请求,当我无法导入 contrib 时。
我该如何解决? (导入错误:没有名为 contrib 的模块)。

2013 年 5 月 3 日星期五下午 1:12,Hugo Osvaldo Barrera <
[email protected]> 写道:

urllib3 对带有 python2 的 SNI 有可选的支持,尽管有一些
可选的依赖项。 (见 urllib3#156https://github.com/shazow/urllib3/pull/156
)。

我相信这应该使用:

从 requests.packages.urllib3.contrib 导入 pyopenssl
pyopenssl.inject_into_urllib3

请注意,默认情况下不导入 contrib 包。

在请求中启用 SNI 基本上有两种选择:

  • 创建函数以手动启用基本上运行上述的 SNI
    代码。 (缺点是用户需要显式启用 SNI
    支持)。
  • 尝试导入先决条件。 如果它们存在,则启用 SNI,否则
    别。

实施这两种选择中的任何一种都没有问题,尽管我更喜欢
知道哪个是请求的首选。 我个人投票赞成
第二种选择。


直接回复本邮件或在Gi tHub上查看
.

request 的 setup.py 不包括那个包(它的来源在那里,但在安装/打包时被排除在外),所以它没有安装,这就是我提到的原因:

将此添加到packages in setup.py
requests.packages.urllib3.contrib

您基本上需要从源代码安装。
如果您有兴趣,请查看我的拉取请求,完成这项工作只需几行。 :)

“如果可选的 deps 可用,请尝试使用 SNI,但仍然使用 SSL,因为我们一直拥有它,但它们不是。”

但是,SSL 并不总是存在。 那是我的观点。 目前,我们尝试使用它,但如果我们没有它并且用户尝试发出 https 请求,则会很快失败。 不过,按照您描述的方式,我的印象是 SNI 会要求用户向 urllib3 传递一些额外的概念,而您只关注它的设置。 如果所有需要的只是#1347,那么我 100% 支持此操作。

如果这是默认值(SNI 支持)和请求,那就太好了
无需任何额外代码或源代码设置即可工作。 对于 urllib3,它的 2
代码行。 为什么不将其添加到请求中。 我是在做白日梦吗? :)

2013 年 5 月 3 日星期五晚上 10:43,Ian Cordasco通知@github.com 写道:

“如果可选的 deps 可用,请尝试使用 SNI,但仍使用 SSL 作为
我们总是有,但他们没有。”

但是,SSL 并不总是存在。 那是我的观点。 目前我们尝试和
使用它,但如果我们没有它并且用户试图制作它,则会很快失败
https 请求。 不过按照你描述的方式,我在
印象 SNI 将要求用户向 urllib3 传递一些额外的概念
而你只专注于它的设置。 如果这一切都是必要的
是#1347 https://github.com/kennethreitz/requests/issues/1347然后我
100%在这背后。


直接回复本邮件或在Gi tHub上查看
.

@pythonmobile旋转顶部。 如果它不停止旋转,你就是在做梦。

inception

为了可能遇到与我相同问题的其他人而发表评论:
如果您在使用requests库发出安全请求时遇到问题,尤其是在尝试访问 Google App Engine 上托管的应用程序时,这可能就是原因。 我看到的错误是“EOF 发生违反协议”。 要诊断此问题,请尝试使用s_client访问同一主机(将example.com替换为相关主机):

openssl s_client -connect example.com:443
openssl s_client -connect example.com:443 -servername example.com

如果第一个命令因“握手失败”而失败,而第二个命令成功,那么您正在尝试访问使用 SNI 的服务器。 当前线程有一些关于如何让requests在这种情况下工作的好信息。 我所做的是尝试在 ipython 中运行from requests.packages.urllib3.contrib import pyopenssl ,并且我继续使用 pip 安装任何导入错误。 天啊。

@mshang 1.2.3 版应该已经为你做这件事了; 你确定你运行的是那个版本?

@hobarrera是的,我正在运行 1.2.3。 requests.packages.urllib3.contrib就在那里,但导入语句仍然抛出了一堆导入错误。 我不得不安装ndg-httpsclient而我忘记了还有什么。

正确的。 请求只是尝试导入所需的模块,如果它不能放弃并继续其生命。 不过,记录在请求中使用 SNI 所需的内容可能是个好主意。

这在requests/packages/urllib3/contrib/pyopenssl.py 中指定

  • pyOpenSSL(使用 0.13 测试)
  • ndg-httpsclient(使用 0.3.2 测试)
  • pyasn1(使用 0.1.6 测试)

(或 python3.2 或更高版本,始终有效)

目前,SNI 的请求和 urllib3 似乎都已损坏。 一
问题是,如果添加 timeout=5.0,则代码的行为与
没有超时。 第二个问题是不存在的域。
与仅依赖于测试相比,测试需要添加更多的 SNI 域
顶点/httpbin/. 它们都根本不反映 SNI 的使用情况。

2013 年 6 月 10 日星期一上午 4:57,Thomas Weißschuh
通知@github.com写道

这在 requests/packages/urllib3/contrib/pyopenssl 中指定。 pyhttps://github.com/kennethreitz/requests/blob/master/requests/packages/urllib3/contrib/pyopenssl.py

  • pyOpenSSL(使用 0.13 测试)
  • ndg-httpsclient(使用 0.3.2 测试)
  • pyasn1(使用 0.1.6 测试)

(或 python3.2 或更高版本,始终有效)


直接回复本邮件或在Gi tHub上查看
.

@pythonmobile如果是这种情况,并且您有一个很好的可重现的测试用例,请在 urllib3 上打开一个突出显示它的问题。 Requests 没有特定于 SNI 的代码(据我所知),所以那里的修复也会修复我们。

除非 urllib3 已经修复,这几天似乎经常发生。 Shazow _et。 al._ 非常棒。 @t-8ch,你们已经看到/修复了吗?

我认为如果我们在请求中编写测试,它们更容易编写和测试,尽管这仅意味着它将主要测试 urllib3 代码。 这样,在请求中每次导入 urllib3 时都可以更轻松地检查 sni 是否损坏并发出警报。 我很快就会写请求测试。

抱歉@pythonmobile ,我不同意。 =)

SNI 是明确的 urllib3 功能。 如果 urllib3 中的 SNI 损坏,您绝对应该为该项目提供修复、测试或至少提供错误报告。 当该项目修复后,请求也将神奇地修复(当我们下次更新 urllib3 时,我们经常这样做)。 =)

虽然对请求进行更多测试肯定不会有什么坏处,但正如@Lukasa所说,如果您希望看到此问题得到实际解决,则需要为 urllib3 编写一个测试。 :)

我们已经进行了许多类似的测试,如果您需要任何帮助,请联系我。

pyOpenSSL 的超时行为似乎与
标准 ssl 模块:

from OpenSSL import SSL
import socket
import ssl

sock = socket.create_connection(('httpbin.org', 443), timeout=4.0)
ssl_sock = ssl.wrap_socket(sock)
ssl_sock.send('GET /ip HTTP/1.1\r\nHost: httpbin.org\r\n\r\n')
print(ssl_sock.recv(10000))

ctx = SSL.Context(SSL.TLSv1_METHOD)
sock = socket.create_connection(('httpbin.org', 443), timeout=4.0)
ctn = SSL.Connection(ctx, sock)
ctn.set_connect_state()

ctn.send('GET /ip HTTP/1.1\r\nHost: httpbin.org\r\n\r\n')
print(sock.read(10000))

这会抛出一个WantReadError ,同样也从 urllib3 中抛出
指定超时时。

文档
这是关于错误的说法:

The operation did not complete; the same I/O method should be called again
later, with the same arguments. Any I/O method can lead to this since new
handshakes can occur at any time.

The wanted read is for dirty data sent over the network, not the clean data
inside the tunnel. For a socket based SSL connection, read means data coming at
us over the network. Until that read succeeds, the attempted
OpenSSL.SSL.Connection.recv, OpenSSL.SSL.Connection.send, or
OpenSSL.SSL.Connection.do_handshake is prevented or incomplete. You probably
want to select() on the socket before trying again. 

我不知道应该如何处理超时。 插座是否神奇
记住select()调用超时或者这是任务
urllib3?
手动跟踪超时听起来并不好笑。

@pythonmobile不存在的域是什么意思。 我跟不上你

@pythonmobile您能否尝试从 shazow/urllib3#233 进行更改并查看代码是否适用于 pyopenssl 和超时?

@t-8ch @pythonmobile :你们也可以看看这个帖子: https :

在 urllib3 或 requests 中的单元测试中获取这些请求会很好。

将这些作为单元测试的问题在于它们只出现在非常特定的配置中。 例如,我从来没有能够在我的任何系统上重现这个问题的后半部分或 #1522,无论是 Windows、OS X 还是 Ubuntu。 这就是为什么我要求@pythonmobile进行可重现的单元测试。 如果我们能找到一个,我们就可以针对它进行开发,否则我们就只能希望 @t-8ch 继续成为天才并神奇地解决我们所有的问题urllib3

注意:@t-8ch,我不认为我对你在这里和urllib3所做的工作表示感谢。 你真棒。 =D:蛋糕::菠萝::香蕉::饼干::啤酒:

@lukasa谢谢 :smile: 我想我可以在将来的某个时间将自己添加到AUTHORS.txt中。

@t-8ch 去做吧。 :+1:

shazow/urllib3#233(现在被拉入 urllib3 master)中的变化为我解决了这个问题( SSLError('bad handshake', WantReadError()) ),这个问题在某些 urls 中发生,有时,在某些配置中:rage4:。 我们可以把它拉进请求主吗?

@rcoup当我们发布 2.0 时,我们会将最新版本加入到请求中。 =)

我正在运行 Python 2.7.6 并且无法安装 pyOpenSSL。 我在 htis 帖子中尝试了解决方法 -> https://stackoverflow.com/questions/18578439/using-requests-with-tls-doesnt-give-sni-support/18579484#18579484

我也不能通过 Python 升级。 还有其他解决方案吗?

我要求我们重新考虑“inject_into_urllib3()”的无条件使用(如果存在)。

7 年前添加,目标是“为 Python 2 添加 SNI 支持”

“urllib3.contrib.pyopenssl.inject_into_urllib3()”被描述为“Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.”:
(https://github.com/urllib3/urllib3/blob/master/src/urllib3/contrib/pyopenssl.py)

理由:
1:安全性/稳定性:用猴子补丁替换第三方库的标准库使用可以说应该更加手术,尤其是对于 ssl。 如果补丁是为了支持 Python2,那么至少检查一个主要版本。 或者更好的是,检查 SNI 支持是否已经存在ssl.HAS_SNI

2:不必要:截至 2014 年 12 月 10 日,Python 3.4 的整个 ssl 模块都已向后移植到 Python 2.7.9。 有关理由,请参阅 PEP 466。 https://www.python.org/downloads/release/python-279/。 这将启用标准库中的 SNI 支持 > v2.7.9

3:不灵活:在实施时,无法禁用此行为。 防止requests使用 pyopenssl 上下文的唯一选择是为我的整个 python 环境卸载 pyopenssl。

此页面是否有帮助?
0 / 5 - 0 等级