尝试从中的响应获取SSL证书requests
。
什么是这样做的好方法?
requests
故意包装这样的低级内容。通常,您唯一要做的就是验证证书是否有效。为此,只需通过即可verify=True
。如果要使用非标准的cacert捆绑包,也可以通过。例如:
resp = requests.get('https://example.com', verify=True, cert=['/path/to/my/ca.crt'])
另外,requests
主要是围绕其他库的一组包装器,主要urllib3
是stdlib的http.client
(或对于2.x而言httplib
)和ssl
。
有时候,答案是只是为了获得在较低级别的对象(例如,resp.raw
是urllib3.response.HTTPResponse
),但在许多情况下,这是不可能的。
这就是其中一种情况。唯一可以看到证书的对象是http.client.HTTPSConnection
(或a
urllib3.connectionpool.VerifiedHTTPSConnection
,但这只是前者的子类)和an
ssl.SSLSocket
,在请求返回时,这些对象都不存在。(connectionpool
顾名思义,该HTTPSConnection
对象存储在一个池中,并且可以在完成后立即重用;该对象SSLSocket
是的成员HTTPSConnection
。)
因此,您需要打补丁,以便可以将数据复制到整个链中。可能就是这样简单:
HTTPResponse = requests.packages.urllib3.response.HTTPResponse
orig_HTTPResponse__init__ = HTTPResponse.__init__
def new_HTTPResponse__init__(self, *args, **kwargs):
orig_HTTPResponse__init__(self, *args, **kwargs)
try:
self.peercert = self._connection.sock.getpeercert()
except AttributeError:
pass
HTTPResponse.__init__ = new_HTTPResponse__init__
HTTPAdapter = requests.adapters.HTTPAdapter
orig_HTTPAdapter_build_response = HTTPAdapter.build_response
def new_HTTPAdapter_build_response(self, request, resp):
response = orig_HTTPAdapter_build_response(self, request, resp)
try:
response.peercert = resp.peercert
except AttributeError:
pass
return response
HTTPAdapter.build_response = new_HTTPAdapter_build_response
这未经测试,因此无法保证;您可能需要修补的更多。
同样,子类化和重写可能比monkeypatching更干净(尤其是因为HTTPAdapter
被设计为子类化)。
或者,甚至更好,分叉urllib3
和requests
,修改分叉,(如果您认为这是合法的话)向上游提交请求。
无论如何,现在,从您的代码中,您可以执行以下操作:
resp.peercert
这将为您提供带有'subject'
和'subjectAltName'
键的字典,由返回pyopenssl.WrappedSocket.getpeercert
。相反,如果您想要有关证书的更多信息,请尝试Christophe
Vandeplas的此答案的变体,该变体]可以让您获得OpenSSL.crypto.X509
对象。如果要获取整个对等证书链,请参阅。
首先,阿巴纳特的答案非常完整。在追随拟议connection-close
的Kalkran问题时,我实际上发现其中peercert不包含有关SSL证书的详细信息。
我深入研究了连接和套接字信息,并提取了self.sock.connection.get_peer_certificate()
包含以下功能的函数:
完成后,代码将变为:
import requests
HTTPResponse = requests.packages.urllib3.response.HTTPResponse
orig_HTTPResponse__init__ = HTTPResponse.__init__
def new_HTTPResponse__init__(self, *args, **kwargs):
orig_HTTPResponse__init__(self, *args, **kwargs)
try:
self.peer_certificate = self._connection.peer_certificate
except AttributeError:
pass
HTTPResponse.__init__ = new_HTTPResponse__init__
HTTPAdapter = requests.adapters.HTTPAdapter
orig_HTTPAdapter_build_response = HTTPAdapter.build_response
def new_HTTPAdapter_build_response(self, request, resp):
response = orig_HTTPAdapter_build_response(self, request, resp)
try:
response.peer_certificate = resp.peer_certificate
except AttributeError:
pass
return response
HTTPAdapter.build_response = new_HTTPAdapter_build_response
HTTPSConnection = requests.packages.urllib3.connection.HTTPSConnection
orig_HTTPSConnection_connect = HTTPSConnection.connect
def new_HTTPSConnection_connect(self):
orig_HTTPSConnection_connect(self)
try:
self.peer_certificate = self.sock.connection.get_peer_certificate()
except AttributeError:
pass
HTTPSConnection.connect = new_HTTPSConnection_connect
您将能够轻松访问结果:
r = requests.get('https://yourdomain.tld', timeout=0.1)
print('Expires on: {}'.format(r.peer_certificate.get_notAfter()))
print(dir(r.peer_certificate))
如果像我一样要忽略SSL证书警告,只需在文件顶部添加以下内容,而不进行SSL验证:
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
r = requests.get('https://yourdomain.tld', timeout=0.1, verify=False)
print(dir(r.peer_certificate))
当然,您可能还希望传递验证证书所需的所有信息,但这更容易,因为它已经通过了顶层。
做这件事的好方法是什么?
问题内容: 我有两个Python脚本。一种使用Urllib2库,另一种使用Requests库。 我发现请求更容易实现,但是找不到urlib2的等效函数。例如: 建立完发布网址后,请给我内容-我正尝试连接到vcloud Director api实例,并且响应显示了我有权访问的端点。但是,如果我按以下方式使用请求库.... .... the和不返回任何内容,即使请求后调用中的状态代码等于200。 为什
问题内容: 尝试在Python中获取HTTP响应内容的原始数据。我有兴趣通过另一个渠道转发响应,这意味着理想情况下,内容应尽可能原始。 什么是做到这一点的好方法? 问题答案: 如果使用呼叫获取HTTP响应,则可以使用响应的属性。这是docs中的代码。
问题内容: 我有一个包含表单(帖子)的html。单击某些提交按钮时,我会收到JSON响应。 如何获取此JSON? 如果我不截取请求,则json将显示在Web视图上,所以我想应该使用(我正在使用API 12),但是我不知道如何在其中获取json。 还是有更好的方法,例如拦截响应而不是请求? 谢谢 问题答案: 您应该重写的方法
我正在使用reverfit/robospice在我构建的应用程序中进行api调用,该应用程序带有一个reverfitGsonSpiceService。所有响应都使用GSON转换器转换为POJO,但是我需要从response头中检索一些信息。我找不到任何获取标头的方法(只有在请求不成功的情况下才能获取标头,因为原始响应是在错误对象中发送的!)如何在转换前截取响应以抓取头?
我正在向一个需要SSL证书才能访问的站点发出请求。当我试图访问URL时,我得到SSL证书错误 文件“C:\program files\python37-32\lib\site-packages\requests\sessions.py”,第533行,在request resp=self.send(prep,**send_kwargs)文件“C:\program files\python37-32\