Saltar al contenido

Validar certificados SSL con Python

Luego de de esta larga selección de información dimos con la solución este atolladero que presentan algunos los usuarios. Te compartimos la respuesta y nuestro objetivo es serte de gran ayuda.

Solución:

He agregado una distribución al Python Package Index que hace que el match_hostname() función de Python 3.2 ssl paquete disponible en versiones anteriores de Python.

http://pypi.python.org/pypi/backports.ssl_match_hostname/

Puedes instalarlo con:

pip install backports.ssl_match_hostname

O puede convertirlo en una dependencia incluida en la lista de su proyecto. setup.py. De cualquier manera, se puede usar así:

from backports.ssl_match_hostname import match_hostname, CertificateError
...
sslsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv3,
                      cert_reqs=ssl.CERT_REQUIRED, ca_certs=...)
try:
    match_hostname(sslsock.getpeercert(), hostname)
except CertificateError, ce:
    ...

Puede usar Twisted para verificar certificados. La API principal es CertificateOptions, que se puede proporcionar como la contextFactory argumento a varias funciones como listenSSL y startTLS.

Desafortunadamente, ni Python ni Twisted vienen con la pila de certificados de CA necesarios para realizar la validación de HTTPS, ni la lógica de validación de HTTPS. Debido a una limitación en PyOpenSSL, todavía no puede hacerlo completamente correctamente, pero gracias al hecho de que casi todos los certificados incluyen un nombre común de asunto, puede acercarse lo suficiente.

Aquí hay una implementación de muestra ingenua de un cliente HTTPS retorcido de verificación que ignora los comodines y las extensiones subjectAltName, y usa los certificados de autoridad de certificación presentes en el paquete ‘ca-certificates’ en la mayoría de las distribuciones de Ubuntu. Pruébelo con sus sitios favoritos de certificados válidos y no válidos :).

import os
import glob
from OpenSSL.SSL import Context, TLSv1_METHOD, VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, OP_NO_SSLv2
from OpenSSL.crypto import load_certificate, FILETYPE_PEM
from twisted.python.urlpath import URLPath
from twisted.internet.ssl import ContextFactory
from twisted.internet import reactor
from twisted.web.client import getPage
certificateAuthorityMap = 
for certFileName in glob.glob("/etc/ssl/certs/*.pem"):
    # There might be some dead symlinks in there, so let's make sure it's real.
    if os.path.exists(certFileName):
        data = open(certFileName).read()
        x509 = load_certificate(FILETYPE_PEM, data)
        digest = x509.digest('sha1')
        # Now, de-duplicate in case the same cert has multiple names.
        certificateAuthorityMap[digest] = x509
class HTTPSVerifyingContextFactory(ContextFactory):
    def __init__(self, hostname):
        self.hostname = hostname
    isClient = True
    def getContext(self):
        ctx = Context(TLSv1_METHOD)
        store = ctx.get_cert_store()
        for value in certificateAuthorityMap.values():
            store.add_cert(value)
        ctx.set_verify(VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, self.verifyHostname)
        ctx.set_options(OP_NO_SSLv2)
        return ctx
    def verifyHostname(self, connection, x509, errno, depth, preverifyOK):
        if preverifyOK:
            if self.hostname != x509.get_subject().commonName:
                return False
        return preverifyOK
def secureGet(url):
    return getPage(url, HTTPSVerifyingContextFactory(URLPath.fromString(url).netloc))
def done(result):
    print 'Done!', len(result)
secureGet("https://google.com/").addCallback(done)
reactor.run()

PycURL hace esto maravillosamente.

A continuación se muestra un breve ejemplo. lanzará un pycurl.error si algo es sospechoso, donde obtiene una tupla con un código de error y un mensaje legible por humanos.

import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.CAINFO, "myFineCA.crt")
curl.setopt(pycurl.SSL_VERIFYPEER, 1)
curl.setopt(pycurl.SSL_VERIFYHOST, 2)
curl.setopt(pycurl.URL, "https://internal.stuff/")

curl.perform()

Probablemente querrá configurar más opciones, como dónde almacenar los resultados, etc. Pero no es necesario saturar el ejemplo con elementos no esenciales.

Ejemplo de las excepciones que se pueden plantear:

(60, 'Peer certificate cannot be authenticated with known CA certificates')
(51, "common name 'CN=something.else.stuff,O=Example Corp,C=SE' does not match 'internal.stuff'")

Algunos enlaces que encontré útiles son libcurl-docs para setopt y getinfo.

  • http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
  • http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html

Si tienes algún recelo o disposición de limar nuestro sección te invitamos realizar una interpretación y con mucho placer lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *