当前位置: 首页 > 面试题库 >

如何从python中的请求获取响应SSL证书?

祁均
2023-03-14
问题内容

尝试从中的响应获取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.rawurllib3.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被设计为子类化)。

或者,甚至更好,分叉urllib3requests,修改分叉,(如果您认为这是合法的话)向上游提交请求。

无论如何,现在,从您的代码中,您可以执行以下操作:

resp.peercert

这将为您提供带有'subject''subjectAltName'键的字典,由返回pyopenssl.WrappedSocket.getpeercert。相反,如果您想要有关证书的更多信息,请尝试Christophe
Vandeplas的此答案的变体,该变体]可以让您获得OpenSSL.crypto.X509对象。如果要获取整个对等证书链,请参阅。

首先,阿巴纳特的答案非常完整。在追随拟议connection-close的Kalkran问题时,我实际上发现其中peercert不包含有关SSL证书的详细信息。

我深入研究了连接和套接字信息,并提取了self.sock.connection.get_peer_certificate()包含以下功能的函数:

  • get_subject() 对于CN
  • get_notAfter()和get_notBefore()到期日期
  • get_serial_number()以及get_signature_algorithm()与加密有关的技术细节

  • 请注意,只有pyopenssl在系统上已安装时,这些才可用。在底层,urllib3使用(pyopenssl如果有),ssl否则使用标准库的模块。在self.sock.connection如下图所示的属性只存在,如果self.sock是urllib3.contrib.pyopenssl.WrappedSocket,不如果它是一个ssl.SSLSocket。您可以安装pyopenssl使用pip install pyopenssl。

完成后,代码将变为:

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\