Python请求SSL主机名不匹配

2024-06-05 23:26:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在尝试访问一个API,该API使用下面给出的python请求库使用SSL进行保护

requests.get('https://path/to/url',cert=('cert.pem','key.pem'),verify='ca.pem')

但我犯了个错误

File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
requests.exceptions.SSLError: hostname '10.10.10.10' doesn't match u'*' # IP address is not real.

如果我的理解是正确的,这个证书可以与任何服务器一起使用,因为它们是用“*”作为域签名的。

我猜请求库正在严格匹配主机名验证,而不是正则表达式匹配。

所以我的问题是,这是请求库的一个bug,还是它的缩进方式?

当我使用下面给出的curl命令时,它工作得非常好。

curl https://path/to/url  --cert cert.pem  --key key.pem --cacert ca.pem

所以我有两种可能,要么curl库不执行主机名验证,要么它们使用正则表达式进行验证。

我哪里做错了?期待一个详细的答案


Tags: topathkeyhttpsapiurlsslget
2条回答

通配符的匹配方式在RFC 2818中有描述,在RFC 6125中有更精确的说明,在CAB baseline requirements中也有信息。最后,浏览器实现了以下功能:

  • 只有最左边的标签可以有通配符,而通配符只与单个标签匹配。这不是像**.*.example.com这样的通配符。同样*.example.com匹配www.example.com,但不匹配sub.www.example.comexample.com
  • 此外,根据公钥后缀有一些限制,即没有浏览器允许使用通配符来表示*.com,有些浏览器不允许使用通配符来表示*.co.uk
  • 在证书中通配符的位置也有限制。subject-alternative-name部分中的所有项都支持通配符,但并非所有项都允许在公用名中使用通配符。
  • 除此之外,通配符只用于主机名。这意味着不允许IP地址与通配符项匹配。若要将IP地址包含在证书中,必须将IP地址用作使用者替代名称(除IE外的所有浏览器)或dNSName(除IE外的所有浏览器)或IP地址必须位于CN中(除Safari外的所有浏览器)。

像python这样的一些语言在过去根本没有对主机名进行任何检查,但是在2.7.9版本中,python默认情况下也会检查主机名,并且有一个与浏览器的操作基本兼容的实现。

至于卷曲:这取决于你使用的卷曲的版本。7.36应该没问题,但旧版本有flaws in the validation

对于通配符在证书中的解释,没有真正的、经过批准的标准。无论它们匹配一个标签,还是多个标签,无论它们是否匹配IP(SAN扩展中的那些绝对不匹配),是否可以匹配标签的一部分(prefix-*.example.com),等等都没有很好的定义。

我建议不要单独使用*,而只使用一个完整的标签(*.example.com)。别把它用在IPs上,只要名字。

相关问题 更多 >