Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Configurar la Seguridad de la Capa de Transporte (TLS)

En esta guía, puedes aprender cómo utilizar el Protocolo TLS para asegurar tu conexión a una implementación de MongoDB.

Cuando activa TLS para una conexión, PyMongo realiza las siguientes acciones:

  • Utiliza TLS para conectarse a la implementación de MongoDB

  • Verifica el certificado de la implementación

  • Garantiza que el certificado certifique la implementación

Para saber cómo configurar su implementación de MongoDB para TLS, consulte la guía de configuración de TLS en el manual de MongoDB Server.

Importante

Una descripción completa de las certificaciones TLS/SSL, PKI (infraestructura de llave pública) y las autoridades de certificación (CA) está más allá del alcance de este documento. Esta página asume conocimientos previos sobre TLS/SSL y acceso a certificados válidos.

Para habilitar TLS para la conexión a tu instancia de MongoDB, establece el tls Opción de conexión a True. Puede hacerlo de dos maneras: pasando un argumento al constructor MongoClient o mediante un parámetro en su cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>", tls=True)
client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>?tls=true")
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>", tls=True)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>?tls=true")

Tip

Si tu cadena de conexión incluye la modificación +srv, que especifica el formato de conexión SRV, TLS está habilitado en tu conexión por defecto.

Para obtener más información sobre el formato de conexión SRV, consulta Formato de conexión SRV en la documentación de MongoDB Server.

Durante el handshake TLS, la implementación de MongoDB presenta a tu aplicación un archivo clave de certificado para establecer su identidad. Por lo general, el certificado de una implementación ha sido firmado por una CA conocida, y tu aplicación depende de esta CA para validar el certificado.

Sin embargo, durante las pruebas es posible que quieras actuar como tu propia CA. En este caso, debes indicar a PyMongo que use tus certificados CA en lugar de los firmados por otra CA.

Para ello, utiliza la opción de conexión tlsCAFile para especificar la ruta a un archivo .pem que contenga la cadena de certificados raíz. Puedes hacer esto de dos maneras: pasando un argumento al constructor MongoClient o mediante un parámetro en tu cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCAFile="/path/to/ca.pem")
uri = "mongodb://<db_username>:<db_password>@<hostname>:<port>/?tls=true&tlsCAFile=/path/to/ca.pem"
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCAFile="/path/to/ca.pem")
uri = "mongodb://<db_username>:<db_password@<hostname>:<port>/?tls=true&tlsCAFile=/path/to/ca.pem"
client = pymongo.AsyncMongoClient(uri)

Cuando un certificado X.509 deja de ser confiable, por ejemplo, si se ha comprometido su llave privada, la CA revoca el certificado. PyMongo incluye dos formas de comprobar si se ha revocado el certificado de un servidor.

Para usar el Protocolo de Estado de Certificados en Línea (OCSP) para validar un certificado de servidor, debes instalar PyMongo con la opción ocsp, como se muestra en el siguiente ejemplo:

python -m pip install pymongo[ocsp]

El proceso de validación de certificados varía según la versión del Servidor MongoDB a la que te conectes:

  • MongoDB v4.4 o posterior: El servidor adjunta una respuesta OCSP con sello de tiempo a su certificado. PyMongo valida el certificado contra la respuesta de OCSP. Si la CA ha revocado el certificado, o si la respuesta OCSP es inválida, el apretón de manos TLS falla.

  • MongoDB v4.3 o anterior: El servidor proporciona un endpoint OCSP, al que PyMongo contacta directamente. PyMongo luego valida el certificado contra la respuesta OCSP. Si la Autoridad de Certificación no ha revocado el certificado, el handshake TLS continúa, incluso si la respuesta OCSP es inválida o está mal formada.

Para evitar que PyMongo contacte con el endpoint OCSP, configure la opción de conexión tlsDisableOCSPEndpointCheck en True. Puedes hacer esto de dos maneras: pasando un argumento al constructor MongoClient o mediante un parámetro en tu cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsDisableOCSPEndpointCheck=True)
uri = "mongodb://example.com/?tls=true&tlsDisableOCSPEndpointCheck=true"
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsDisableOCSPEndpointCheck=True)
uri = "mongodb://example.com/?tls=true&tlsDisableOCSPEndpointCheck=true"
client = pymongo.AsyncMongoClient(uri)

Nota

Incluso si la opción tlsDisableOCSPEndpointCheck está configurada en True, PyMongo sigue verificando cualquier respuesta OCSP adjunta al certificado de un servidor.

En lugar de usar OCSP, puedes indicar a PyMongo que verifique el certificado del servidor contra una Lista de revocación de certificados (CRL) publicada por la CA. Para hacerlo, utiliza la opción de conexión tlsCRLFile para especificar la ruta hacia un archivo .pem o .der de la CA. Puedes hacerlo de dos maneras: pasando un argumento al constructor MongoClient o a través de un parámetro en la cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCRLFile="/path/to/crl.pem")
uri = "mongodb://example.com/?tls=true&tlsCRLFile=/path/to/crl.pem"
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCRLFile="/path/to/crl.pem")
uri = "mongodb://example.com/?tls=true&tlsCRLFile=/path/to/crl.pem"
client = pymongo.AsyncMongoClient(uri)

Nota

No se puede usar tanto una CRL como un OCSP en el mismo handshake TLS.

Algunas implementaciones de MongoDB requieren que cada aplicación que se conecte presente un certificado de cliente que acredite su identidad. Para especificar el certificado de cliente que PyMongo debe presentar, configure la opción tlsCertificateKeyFile en la ruta del archivo del archivo .pem que contiene el certificado y la llave privada. Puedes hacer esto de dos formas: pasando un argumento al constructor MongoClient o a través de un parámetro en tu cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCertificateKeyFile='/path/to/client.pem')
uri = ("mongodb://<db_username>:<db_password>@<hostname:<port>/?"
"tls=true"
"&tlsCertificateKeyFile=path/to/client.pem")
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCertificateKeyFile='/path/to/client.pem')
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsCertificateKeyFile=path/to/client.pem")
client = pymongo.AsyncMongoClient(uri)

Importante

Su certificado de cliente y su clave privada deben estar en el mismo archivo .pem. Si están almacenados en archivos diferentes, debe concatenarlos. El siguiente ejemplo muestra cómo concatenar un archivo de clave y un archivo de certificado en un tercer archivo llamado combined.pem en un sistema Unix:

$ cat key.pem cert.pem > combined.pem

Si la clave privada de su archivo de certificado está cifrada, debe proporcionar una contraseña. Para ello, utilice la opción de conexión tlsCertificateKeyFilePassword para especificar la contraseña o frase de contraseña de la clave privada cifrada. Puede hacerlo de dos maneras: pasando un argumento al constructor MongoClient o mediante un parámetro en su cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>",
tls=True,
tlsCertificateKeyFile='/path/to/client.pem',
tlsCertificateKeyFilePassword=<passphrase>)
uri = ("mongodb://<db_username>:<db_password>@<hostname:<port>/?"
"tls=true"
"&tlsCertificateKeyFile=path/to/client.pem"
"&tlsCertificateKeyFilePassword=<passphrase>")
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsCertificateKeyFile='/path/to/client.pem',
tlsCertificateKeyFilePassword=<passphrase>)
uri = ("mongodb://<db_username>:<db_password"
"@<hostname>:<port>/?"
"tls=true"
"&tlsCertificateKeyFile=path/to/client.pem"
"&tlsCertificateKeyFilePassword=<passphrase>")
client = pymongo.AsyncMongoClient(uri)

Cuando TLS está activado, PyMongo verifica automáticamente el certificado que presenta el servidor. Cuando pruebe su código, puede deshabilitar esta verificación. Esto se conoce como TLS no seguro.

Cuando TLS inseguro está activado, PyMongo solo requiere que el servidor presente un certificado X.509. El controlador acepta un certificado aun si se cumple alguna de las siguientes condiciones:

  • El nombre de host del servidor y el nombre del sujeto (o nombre alternativo del sujeto) en el certificado no coinciden.

  • El certificado está caducado o todavía no es válido.

  • El certificado no tiene un certificado raíz confiable en la cadena.

  • El propósito del certificado no es válido para la identificación del servidor.

Nota

Incluso cuando está habilitado TLS inseguro, la comunicación entre el cliente y el servidor está cifrada con TLS.

Para habilitar TLS inseguro, configure la opción de conexión tlsInsecure en True. Puedes hacer esto de dos maneras: pasando un argumento al constructor MongoClient o mediante un parámetro en tu cadena de conexión.

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>",
tls=True,
tlsInsecure=True)
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsInsecure=true")
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsInsecure=True)
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsInsecure=true")
client = pymongo.AsyncMongoClient(uri)

Para desactivar únicamente la validación del certificado, establece la opción tlsAllowInvalidCertificates en True y la opción tlsInsecure en False o déjala fuera:

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsAllowInvalidCertificates=True)
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsAllowInvalidCertificates=true")
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsAllowInvalidCertificates=True)
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsAllowInvalidCertificates=true")
client = pymongo.AsyncMongoClient(uri)

Para desactivar únicamente la verificación del nombre de host, establece la opción tlsAllowInvalidHostnames en True, y ajusta la opción tlsInsecure a False o déjala fuera:

client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsAllowInvalidHostnames=True)
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsAllowInvalidHostnames=true")
client = pymongo.MongoClient(uri)
client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",
tls=True,
tlsAllowInvalidHostnames=True)
uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"
"tls=true"
"&tlsAllowInvalidHostnames=true")
client = pymongo.AsyncMongoClient(uri)

Advertencia

No utilizar en producción

Siempre establece las opciones tlsInsecure, tlsAllowInvalidCertificates y tlsAllowInvalidHostnames en False en producción.

Establecer cualquiera de estas opciones en True en un entorno de producción hace que tu aplicación sea insegura y potencialmente vulnerable a certificados expirados y a procesos externos que se hacen pasar por instancias válidas de clientes.

Un mensaje de error similar al siguiente significa que OpenSSL no pudo verificar el certificado del servidor:

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

Esto ocurre a menudo porque OpenSSL no puede acceder a los certificados raíz del sistema o porque los certificados están desactualizados.

Si usa Linux, asegúrese de tener instaladas las últimas actualizaciones del certificado raíz de su proveedor de Linux.

Si utilizas macOS y ejecutas la versión3.7 o posterior de Python que descargaste desde python.org, ejecuta el siguiente comando para instalar los certificados raíz:

open "/Applications/Python <YOUR PYTHON VERSION>/Install Certificates.command"

Tip

Para más información sobre este problema, consulta Problema de Python 29065.

Si utiliza portable-pypy, posiblemente tenga que configurar una variable de entorno para indicarle a OpenSSL dónde encontrar los certificados raíz. El siguiente ejemplo de código muestra cómo instalar el módulo certifi desde PyPi y exportar la variable de entorno SSL_CERT_FILE:

$ pypy -m pip install certifi
$ export SSL_CERT_FILE=$(pypy -c "import certifi; print(certifi.where())")

Un mensaje de error similar al siguiente significa que la versión de OpenSSL que usa Python no admite un protocolo TLS lo suficientemente nuevo para conectarse al servidor:

[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version

Las mejores prácticas de la industria recomiendan, y algunas normativas exigen, que se inhabiliten protocolos TLS antiguos en algunas implementaciones de MongoDB. Algunas implementaciones podrían deshabilitar TLS 1.0, mientras que otras podrían deshabilitar TLS 1.0 y TLS 1.1.

No se requieren cambios en la aplicación para que PyMongo utilice las versiones más nuevas de TLS, pero es posible que algunas versiones del sistema operativo no proporcionen una versión de OpenSSL lo suficientemente nueva como para soportarlas.

Si usas macOS v10.12 (High Sierra) o anterior, instala Python desde python.org, homebrew, macports u otra fuente similar.

Si usa Linux u otro Unix que no sea macOS, utilice el siguiente comando para comprobar su versión de OpenSSL:

$ openssl version

Si el comando anterior muestra un número de versión menor que 1.0.1, no se encuentra disponible soporte para TLS 1.1 o versiones más recientes. Actualiza a una versión más reciente o contacta con tu proveedor de sistema operativo para encontrar una solución.

Para comprobar la versión TLS de su intérprete de Python, instale el módulo requests y ejecute el siguiente código:

python -c "import requests; print(requests.get('https://www.howsmyssl.com/a/check', verify=False).json()['tls_version'])"

Debería ver TLS 1.1 o posterior.

Un mensaje de error similar al siguiente significa que la comprobación de revocación del certificado falló:

[('SSL routines', 'tls_process_initial_server_flight', 'invalid status response')]

Para obtener más detalles, consulta la sección OCSP de esta guía.

Al utilizar Python v3.10 o posterior con versiones de MongoDB anteriores a la v4.0, puedes ver errores similares a los siguientes mensajes:

SSL handshake failed: localhost:27017: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)
SSL handshake failed: localhost:27017: EOF occurred in violation of protocol (_ssl.c:997)

Los registros del MongoDB Server también podrían mostrar el siguiente error:

2021-06-30T21:22:44.917+0100 E NETWORK [conn16] SSL: error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher

Cambios realizados en el módulo SSL en Python v3.10 podría causar incompatibilidades con versiones de MongoDB anteriores a la v4.0. Para resolver este problema, intenta uno o más de los siguientes pasos:

  • Degradar Python a la versión3.9 o anterior

  • Actualiza MongoDB Server a v4.2 o posterior

  • Instala PyMongo con la opción OCSP, que depende de PyOpenSSL

Al utilizar OpenSSL v3 o posterior, es posible que vea un error similar al siguiente mensaje:

[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled

Este tipo de errores ocurren debido a servidores proxy SSL obsoletos o con errores que aplican por error la renegociación de TLS heredada.

Para resolver este problema, realiza los siguientes pasos:

1

Ejecute el siguiente comando para asegurarse de que tiene instalado OpenSSL vv3.0.4 o posterior:

openssl version
2

Cree un archivo de configuración que incluya la opción UnsafeLegacyServerConnect. El siguiente ejemplo muestra cómo configurar la opción UnsafeLegacyServerConnect:

openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
Options = UnsafeLegacyServerConnect
3

Ejecute Python mientras configura la variable de entorno OPENSSL_CONF para usar el archivo de configuración OpenSSL que acaba de crear:

OPENSSL_CONF=/path/to/the/config/file/above.cnf python ...

Importante

Dado que establecer la opción UnsafeLegacyServerConnect tiene implicaciones de seguridad, utilice esta solución temporal como último recurso para abordar los errores unsafe legacy renegotiation disabled.

Para obtener más información sobre cómo configurar TLS para PyMongo, consulta la siguiente documentación de la API:

Volver

Encriptación en uso