有没有一种简单的方法来检查网站是否有SSL证书

时间:2012-02-01 16:23:17

标签: python ssl

使用urllib2 / SSL?

我有一个很大的域列表,知道是否有任何我不知道的ssl证书会很有用。

1 个答案:

答案 0 :(得分:4)

我不确定使用urllib2。不幸的是,我能找到的最近的信息是this link和相关的代码:

import socket
import ssl

HOST = "www.google.com"
PORT = 443

# replace HOST name with IP, this should fail connection attempt
HOST = socket.getaddrinfo(HOST, PORT)[0][4][0]
print(HOST)

# create socket and connect to server
# server address is specified later in connect() method
sock = socket.socket()
sock.connect((HOST, PORT))

# wrap socket to add SSL support
sock = ssl.wrap_socket(sock,
  # flag that certificate from the other side of connection is required
  # and should be validated when wrapping 
  cert_reqs=ssl.CERT_REQUIRED,
  # file with root certificates
  ca_certs="cacerts.txt"
)

# security hole here - there should be an error about mismatched host name
# manual check of hostname
cert = sock.getpeercert()
for field in cert['subject']:
  if field[0][0] == 'commonName':
    certhost = field[0][1]
    if certhost != HOST:
      raise ssl.SSLError("Host name '%s' doesn't match certificate host '%s'"
                         % (HOST, certhost))

虽然文件中的注释相当广泛,但第一个链接中的wiki也列出了这些说明:

  

要验证证书是否与请求的站点匹配,您需要检查证书的commonName中的subject字段。可以使用getpeercert()包装套接字方法访问此信息。

     

您需要cacerts.txt文件,其中包含与脚本一起放置的根证书 - 请参阅下文如何获取更新列表。要检查证书验证是否有效,请使用https://www.debian-administration.org/名称中的HOST。此站点的证书未由cacerts.txt的任何根证书签名,因此您将收到错误消息。

您也可以查看pyopenssl module,因为根据我发布的第一个链接,它可用于以这种方式验证SSL证书:

import socket
from OpenSSL import SSL

HOST = "www.google.com"
PORT = 443

# replace HOST name with IP, this should fail connection attempt,
# but it doesn't by default
HOST = socket.getaddrinfo(HOST, PORT)[0][4][0]
print(HOST)

# uses HOST
def verify_cb(conn, x509, errno, errdepth, retcode):
  """
  callback for certificate validation
  should return true if verification passes and false otherwise
  """
  if errno == 0:
    if errdepth != 0:
      # don't validate names of root certificates
      return True
    else:
      if x509.get_subject().commonName != HOST:
        return False
  else:
    return False

context = SSL.Context(SSL.SSLv23_METHOD)
context.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb)
context.load_verify_locations("cacerts.txt")

# create socket and connect to server
sock = socket.socket()
sock = SSL.Connection(context, sock)
sock.connect((HOST, PORT))
sock.do_handshake()

根据第一个链接中的文档,对于这些示例,您将需要here中的最新证书版本。