简体   繁体   English

在Python中禁用SSL证书验证

[英]Disable SSL certificate validation in Python

I'm writing a script that connects to a bunch of URLs over HTTPS, downloads their SSL certificate and extracts the CN. 我正在编写一个脚本,通过HTTPS连接到一堆URL,下载他们的SSL证书并提取CN。 Everything works except when I stumble on a site with an invalid SSL certificate. 一切都有效,除非我偶然发现一个SSL证书无效的网站。 I absolutely do not care if the certificate is valid or not. 我绝对不在乎证书是否有效。 I just want the CN but Python stubbornly refuses to extract the certificate information if the certificate is not validated. 我只想要CN,但如果证书未经过验证,Python就会顽固地拒绝提取证书信息。 Is there any way to get around this profoundly stupid behavior? 有没有办法绕过这种极其愚蠢的行为? Oh, I'm using the built-in socket and ssl libraries only. 哦,我只使用内置套接字和ssl库。 I don't want to use third-party libraries like M2Crypto or pyOpenSSL because I'm trying to keep the script as portable as possible. 我不想使用像M2Crypto或pyOpenSSL这样的第三方库,因为我试图让脚本尽可能地保持可移植性。

Here's the relevant code: 这是相关的代码:

    file = open("list.txt", "r")
    for x in file:
    server = socket.getaddrinfo(x.rstrip(), "443")[0][4][0]
    sslsocket = socket.socket()
    sslsocket.connect((server, 443))
    sslsocket = ssl.wrap_socket(sslsocket, cert_reqs=ssl.CERT_REQUIRED, ca_certs="cacerts.txt")
    certificate = sslsocket.getpeercert()`

The ssl.get_server_certificate can do it: ssl.get_server_certificate可以这样做:

import ssl
ssl.get_server_certificate(("www.sefaz.ce.gov.br",443)) 

I think function doc string is more clear than python doc site: 我认为函数doc字符串比python doc site更清晰:

"""Retrieve the certificate from the server at the specified address,
   and return it as a PEM-encoded string.
   If 'ca_certs' is specified, validate the server cert against it.
   If 'ssl_version' is specified, use it in the connection attempt."""

So you can extract common name from binary DER certificate searching for common name object identifier: 因此,您可以从二进制DER证书中提取通用名称,以搜索通用名称对象标识符:

def get_commonname(host,port=443):
    oid='\x06\x03U\x04\x03' # Object Identifier 2.5.4.3 (COMMON NAME)
    pem=ssl.get_server_certificate((host,port))
    der=ssl.PEM_cert_to_DER_cert(pem)
    i=der.find(oid) # find first common name (certificate authority)
    if i!=-1:
        i=der.find(oid,i+1) # skip and find second common name
        if i!=-1:
            begin=i+len(oid)+2
            end=begin+ord(der[begin-1])
            return der[begin:end]
    return None

Ok. 好。 I cleaned up olivecoder's code to solve the problem that it assumes there will always be three CNs in the certificate chain (root, intermediate, server) and I condensed it. 我清理了olivecoder的代码,以解决它假设证书链中总共有三个CN(根,中间,服务器)的问题,并且我将它压缩了。 This is the final code I will be using. 这是我将要使用的最终代码。

cert = ssl.get_server_certificate(("www.google.com", 443)) #Retrieve SSL server certificate
cert = ssl.PEM_cert_to_DER_cert(cert) #Convert certificate to DER format
begin = cert.rfind('\x06\x03\x55\x04\x03') + 7 #Find the last occurence of this byte string indicating the CN, add 7 bytes to startpoint to account for length of byte string and padding
end = begin + ord(cert[begin - 1]) #Set endpoint to startpoint + the length of the CN
print cert[begin:end] #Retrieve the CN from the DER encoded certificate

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM