我正在使用httplib2从我的服务器向另一个Web服务发出请求。我们想要使用相互证书身份验证。我看到如何使用证书进行传出连接(h.set_certificate
),但如何检查应答服务器使用的证书?
This ticket似乎表明httplib2本身并不这样做,并且对于在哪里查看只有模糊的建议。
有可能吗?我是否需要在较低级别进行攻击?
答案 0 :(得分:5)
以下是我的同事Dave St. Germain为解决问题所写的代码:
import ssl
import socket
from httplib2 import has_timeout
import httplib2
import socks
class CertificateValidationError(httplib2.HttpLib2Error):
pass
def validating_sever_factory(ca_cert_file):
# we need to define a closure here because we don't control
# the arguments this class is instantiated with
class ValidatingHTTPSConnection(httplib2.HTTPSConnectionWithTimeout):
def connect(self):
# begin copypasta from HTTPSConnectionWithTimeout
"Connect to a host on a given (SSL) port."
if self.proxy_info and self.proxy_info.isgood():
sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM)
sock.setproxy(*self.proxy_info.astuple())
else:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if has_timeout(self.timeout):
sock.settimeout(self.timeout)
sock.connect((self.host, self.port))
# end copypasta
try:
self.sock = ssl.wrap_socket(sock,
self.key_file,
self.cert_file,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs=ca_cert_file
)
except ssl.SSLError:
# we have to capture the exception here and raise later because
# httplib2 tries to ignore exceptions on connect
import sys
self._exc_info = sys.exc_info()
raise
else:
self._exc_info = None
# this might be redundant
server_cert = self.sock.getpeercert()
if not server_cert:
raise CertificateValidationError(repr(server_cert))
def getresponse(self):
if not self._exc_info:
return httplib2.HTTPSConnectionWithTimeout.getresponse(self)
else:
raise self._exc_info[1], None, self._exc_info[2]
return ValidatingHTTPSConnection
def do_request(url,
method='GET',
body=None,
headers=None,
keyfile=None,
certfile=None,
ca_certs=None,
proxy_info=None,
timeout=30):
"""
makes an http/https request, with optional client certificate and server
certificate verification.
returns response, content
"""
kwargs = {}
h = httplib2.Http(proxy_info=proxy_info, timeout=timeout)
is_ssl = url.startswith('https')
if is_ssl and ca_certs:
kwargs['connection_type'] = validating_sever_factory(ca_certs)
if is_ssl and keyfile and certfile:
h.add_certificate(keyfile, certfile, '')
return h.request(url, method=method, body=body, headers=headers, **kwargs)
答案 1 :(得分:3)
自问题以来,事情可能已经发生了变化,我可以使用httplib2 v0.7进行相互身份验证,如下所示:
import httplib2
h=httplib2.Http(ca_certs='ca.crt')
h.add_certificate(key='client_private_key.pem', cert='cert_client.pem', domain='')
try: resp, cont = h.request('https://mytest.com/cgi-bin/test.cgi')
except Exception as e: print e
注意domain=''
参数,这是我能使它工作的唯一方法