2013-06-03 40 views

Trả lời

8

requests cố tình kết thúc tốt đẹp thứ cấp thấp như thế này. Thông thường, điều duy nhất bạn muốn làm là verify that the certs are valid. Để làm điều đó, chỉ cần vượt qua verify=True. Nếu bạn muốn sử dụng một gói cacert không chuẩn, bạn cũng có thể truyền nó. Ví dụ:

resp = requests.get('https://example.com', verify=True, cert=['/path/to/my/ca.crt']) 

Ngoài ra, requests chủ yếu là một bộ các hàm bao quanh các thư viện khác, chủ yếu là urllib3 và của stdlib http.client (hoặc, đối với 2.x, httplib) và ssl.

Đôi khi, câu trả lời chỉ là nhận được ở các đối tượng cấp thấp hơn (ví dụ: resp.rawurllib3.response.HTTPResponse), nhưng trong nhiều trường hợp không thể.

Và đây là một trong những trường hợp đó. Các đối tượng duy nhất từng thấy certs là http.client.HTTPSConnection (hoặc urllib3.connectionpool.VerifiedHTTPSConnection, nhưng đó chỉ là một phân lớp của trước đây) và một số ssl.SSLSocket và không tồn tại trong số đó nữa vào thời điểm yêu cầu trả về. (Như tên connectionpool ngụ ý, đối tượng HTTPSConnection được lưu trữ trong một hồ bơi, và có thể được tái sử dụng càng sớm càng hoàn thành công việc; các SSLSocket là một thành viên của HTTPSConnection.)

Vì vậy, bạn cần phải vá thứ để bạn có thể sao chép dữ liệu lên chuỗi. Nó có thể đơn giản như thế này:

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 

Đó là chưa được kiểm tra, vì vậy không đảm bảo; bạn có thể cần phải vá nhiều hơn thế.

Ngoài ra, phân lớp và ghi đè có thể sẽ sạch hơn so với bắt chước (đặc biệt là từ HTTPAdapter được thiết kế để được phân lớp).

Hoặc, thậm chí tốt hơn, giả mạo urllib3requests, sửa đổi ngã ba của bạn và (nếu bạn cho rằng điều này là hữu ích hợp pháp), hãy gửi yêu cầu kéo ngược dòng.

Dù sao, bây giờ, từ mã của bạn, bạn có thể làm điều này:

resp.peercert 

Tất nhiên bạn cũng có thể muốn vượt qua cùng tất cả các thông tin cần thiết để xác minh các CERT, nhưng điều đó thậm chí còn dễ dàng hơn, bởi vì nó đã đi qua cấp cao nhất.

+0

Ồ, điều này rất hoàn chỉnh. Cảm ơn rất nhiều! Tôi sẽ làm việc trên nó và xem nó như thế nào. Cảm ơn một lần nữa! –

5

này, mặc dù không đẹp chút nào, hoạt động:

import requests 

req = requests.get('https://httpbin.org') 
pool = req.connection.poolmanager.connection_from_url('https://httpbin.org') 
conn = pool.pool.get() 
# get() removes it from the pool, so put it back in 
pool.pool.put(conn) 
print(conn.sock.getpeercert()) 
+1

Điều này chỉ hoạt động nếu kết nối vẫn còn hoạt động, điều này không được đảm bảo. Ví dụ, nếu phía bên kia gửi một 'Connection: close'. Hoặc nếu bạn đã gửi các yêu cầu khác (đặc biệt nếu bạn đang sử dụng điều này trong ngữ cảnh không đồng bộ hoặc luồng). Hoặc nếu 'urllib3' chỉ cảm thấy như nó không có lý do rõ ràng. – abarnert

1

Để bắt đầu, abarnert's answer là rất đầy đủ

Nhưng tôi muốn thêm, rằng trong trường hợp bạn đang tìm kiếm các chuỗi cert bạn bè, bạn sẽ cần phải vá thêm một đoạn mã

import requests 
sock_requests = requests.packages.urllib3.contrib.pyopenssl.WrappedSocket 
def new_getpeercertchain(self,*args, **kwargs): 
    x509 = self.connection.get_peer_cert_chain() 
    return x509 
sock_requests.getpeercertchain = new_getpeercertchain 

sau đó bạn có thể gọi nó là một cách rất tương tự như câu trả lời chấp nhận

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.peercertchain = self._connection.sock.getpeercertchain() 
    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.peercertchain = resp.peercertchain 
    except AttributeError: 
     pass 
    return response 
HTTPAdapter.build_response = new_HTTPAdapter_build_response 

bạn sẽ nhận được resp.peercertchain chứa một tuple của OpenSSL.crypto.X509 đối tượng

Các vấn đề liên quan