不行了,找遍了国外社区都解决不掉,召唤大神的出现。python requests 在 Debian/Ubuntu 上无法进行 TLS 握手?

2015-09-30 22:37:06 +08:00
 adrianzhang
有个用 Requests 的脚本,访问 https://dictation.nuancemobility.net 这个 URL 。但是奇怪的是在 CentOS 可以正常工作,从服务器获得 200 响应,放到 Debian/Ubuntu 上就只能从服务器获得 500 响应。
这个代码如下:

<pre><code>

class Nuance_api():

def __init__(self, appid, appkey, n_id):
self.appid = appid
self.appkey = appkey
self.id = n_id

def recogenize(self, language, voicefile):
nuance_url = 'https://dictation.nuancemobility.net/NMDPAsrCmdServlet/dictation'
n_params = {'appId':self.appid, 'appKey':self.appkey, 'id':self.id}
voice_file = {'file': open(voicefile, 'rb')}
n_headers = {'Accept-Language':language, 'Content-Type':'audio/amr;codec=amr;bit=4.75;rate=8000', 'Accept':'text/plain', 'Accept-Topic':'Dictation'}
r = requests.post(url=nuance_url, params=n_params, headers=n_headers, files=voice_file, verify=False)
if r.status_code == 200 :
return r.text

</code></pre>

由于涉及到隐私的 key 等信息,单用这段代码测试比较麻烦。可以说明的是,这段代码在 CentOS 没有任何问题,可以返回识别的 text.

那么,事情就集中到: Debian/Ubuntu 上的 requests 为什么就不能像 CentOS 一样工作?

经过一些 debug ,这个服务器使用 TLS v1.2 或 v1 来进行握手,那么我甚至将代码改写为强制使用 TLS v1.2 ,在 Debian/Ubuntu 上同样失败。抓包显示,握手后服务端连续发来 4 个 hello ,但是在 CentOS 上的抓包显示为握手后就开始传输数据了。这表明握手并不成功(至少我这么认为)。

有些文章说 Debian/Ubuntu 上的 openssl 默认不设定任何 CA bundle ,但是 Requests 使用的是自己的 CA bundle ,为了测试,特意在代码中将 verify='我的 cacert.pem',当我的 cacert.pem 里没有任何 root certificate 的时候,确实是 ssl verify failure ,加上该网站证书链里的顶级 VeriSign Class 3 证书,就可以通过验证。所以, CA bundle 不是症结。

那么,究竟为什么。到底 Debian/Ubuntu 上使用 Requests 的正确姿势是什么呢?

盼望这里有大神有些许经验。 Stackoverflow, GitHub 在这个问题上都阵亡了。满世界都是 ssl 验证不通过的问题,但是能有效解决的很少。涉及 requests ,那就更少了。
4024 次点击
所在节点    Python
21 条回复
msg7086
2015-09-30 22:50:41 +08:00
握手失败的时候竟然能从服务器那边获取到 500 错误?手握在什么东西上了?
pc10201
2015-09-30 22:56:35 +08:00
zjxubinbin
2015-09-30 23:02:29 +08:00
@msg7086 应该是握在蛋上面了~
alexapollo
2015-09-30 23:05:52 +08:00
pip install pyopenssl ndg-httpsclient pyasn1
可以试试
187j3x1
2015-09-30 23:09:01 +08:00
这跟放一段伪代码有什么区别
mengzhuo
2015-09-30 23:14:51 +08:00
ca 库地址设置
python 编译时的 openssl 版本
ryd994
2015-09-30 23:31:06 +08:00
@pc10201
@mengzhuo
能获得 500 就根本不是 SSL 错误
HTTP500 是 7 层的啊

不加任何 header ,找个 https 的网站试试,随便找个 https 的登录页面
Strikeactor
2015-09-30 23:37:21 +08:00
@msg7086 JB 上
逃(
adrianzhang
2015-09-30 23:38:00 +08:00
@msg7086 说的有道理。那请教一下这个握手之后,服务器为什么会发过来 4 个 hello ?一定有什么不同寻常的事情发生了。

@pc10201 关闭了也不行,代码里可以看到 verify=False 的。这是最初的代码,不通过后才想尽办法加 ca 等,开启验证找问题的。


@alexapollo 谢谢。我去试试看。


@187j3x1 你说咋办?把 id 和 key 都放上来?这个代码很特殊在于有一定的 headers 和 parameters ,以及传输文件,如果用别的网站做演示的话,没法复现错误啊。


@mengzhuo Requests 使用的是自己带的 CA bundle ,在 /usr/local/lib/python2.7/site-packages/requests/cacert.pem 。用 verify=开关设置为自己定的 pem ,这个实验在问题中提到了。 python 和 openssl 版本是这样的:
1) 从 ISO 安装的 ElementoryOS Luna (基于 Ubuntu 12.02 )
2) 或 Freya(基于 Ubuntu 14.04 TLS)
3) 官方 Docker python 2.7.10 镜像(基于 Debian)
这三个环境都是从 ISO 安装后未作任何特殊设置。因此 python 以及 openssl 版本等信息可以从这些环境里得到。比如直接 run 一个 docker python 2.7.0 。请看下 CentOS, python 2.6.6, OpenSSL 1.0.1e-fips 11 Feb 2013 。

刚才又做了个测试,在 Debian/Ubuntu 上,使用 curl 是成功的,问题一定出在 python, openssl, requests 这几个中间。
adrianzhang
2015-09-30 23:38:57 +08:00
@ryd994 如果使用 https://www.google.com ,是没有任何问题的。这个特殊情况只出现在这个特殊场景下。
adrianzhang
2015-09-30 23:58:44 +08:00
@alexapollo 仍然无法获取正确响应。
adrianzhang
2015-09-30 23:59:39 +08:00
@zjxubinbin
@Strikeactor
大神们我错了行不?给个建设性意见好不好?
binux
2015-10-01 00:04:57 +08:00
UA
binux
2015-10-01 00:11:22 +08:00
requests 版本差异没见提到
azurefang
2015-10-01 00:18:35 +08:00
楼主你试着装一下 python2.7.9
alexapollo
2015-10-01 00:22:53 +08:00
https://dictation.nuancemobility.net/ 怎么普通的点进去都是 500 。。而且你没看 500 的完整回复吗?
我猜是有什么特殊的配置写在代码里了。
adrianzhang
2015-10-01 00:36:47 +08:00
@binux UA 应该不是问题,因为同样的代码在 CentOS 上是 work 的。 requests 在 debian 里是 requests==2.7.0
在 centos 上是 requests==1.2.3

@azurefang 谢谢,我一会儿测试下 2.7.9

@alexapollo 是的,代码没有给出必要的 credentials ,因为涉及隐私内容没法放到公共空间里,这个完整 URL 是有 headers, parameters, file, 请看代码。有空我去申请个测试的帐号。

感谢各位,现在联系到了 Requests 的作者,正在跟他沟通做 debug 。如果各位还有什么需要我提供的也请继续回复,我会持续 post.
binux
2015-10-01 00:45:43 +08:00
@adrianzhang requests 默认 UA 会带上系统信息的, 而且你这个版本差太多了啊!
adrianzhang
2015-10-01 01:13:50 +08:00
@binux 谢谢了!还真是版本差异产生的,见题目上我的补充。
dingyaguang117
2015-10-01 06:31:10 +08:00
没有用 requirements 并且固定版本号的习惯呀。。。

之前同样的代码, python 版本不一样也会有问题。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/224900

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX