Join us Sept 17 at .local NYC! Use code WEB50 to save 50% on tickets. Learn more >
MongoDB Event
Menu Docs
Página inicial do Docs
/ / /
Driver Pymongo
/

Configurar o TLS (Transport Layer Security)

Neste guia, você pode aprender como usar o protocoloTLS do para proteger sua conexão para uma implantação MongoDB .

Quando você habilita o TLS para uma conexão, o PyMongo executa as seguintes ações:

  • Usa TLS para se conectar ao MongoDB deployment

  • Verifica o certificado do sistema

  • Garante que o certificado certifique o sistema

Para saber como configurar seu sistema MongoDB para TLS, consulte o guia de configuração TLS no manual do MongoDB Server .

Importante

Uma descrição completa de certificados TLS/SSL, PKI (Public Key Infrastructure) e Autoridades de Certificação (CAs) está além do escopo deste documento. Esta página pressupõe conhecimento prévio de TLS/SSL e acesso a certificados válidos.

Para habilitar o TLS para a conexão com sua instância do MongoDB, defina a opção de conexão tls como True. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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")

Dica

Se a string de conexão incluir a modificação +srv , que especifica o formato de conexão SRV, o TLS será habilitado na sua conexão por padrão.

Para saber mais sobre o formato de conexão SRV, consulte Formato de conexão SRV na documentação do MongoDB Server .

Durante a negociação TLS, o sistema do MongoDB apresenta um arquivo de chave de certificado para seu aplicativo para estabelecer sua identidade. Normalmente, o certificado de um sistema é assinado por uma CA conhecida, e seu aplicativo depende dessa CA para validar o certificado.

No entanto, durante os testes, você pode querer agir como sua própria CA. Nesse caso, você deve instruir o PyMongo a usar seus certificados de CA em vez dos assinados por outra CA.

Para fazer isso, use a opção de conexão tlsCAFile para especificar o caminho para um arquivo .pem que contém a cadeia de certificados raiz. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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)

Quando um certificado X.509 não é mais confiável - por exemplo, se sua chave privada foi comprometida - a CA revoga o certificado. O PyMongo inclui duas maneiras de verificar se o certificado de um servidor foi revogado.

Para usar o Protocolo de Status do Certificado On-line (OCSP) para validar um certificado de servidor, você deve instalar o PyMongo com a opção ocsp , conforme mostrado no exemplo a seguir:

python -m pip install pymongo[ocsp]

O processo de validação do certificado varia dependendo da versão do MongoDB Server à qual você está se conectando:

  • MongoDB v4.4 ou posterior: o servidor grampeia uma resposta OCSP com registro de data e hora em seu certificado. O PyMongo valida o certificado em relação à resposta do OCSP. Se a CA tiver revogado o certificado ou se a resposta OCSP for inválida, a negociação TLS falhará.

  • MongoDB v4.3 ou anterior: o servidor fornece um endpoint OCSP, com o qual o PyMongo entra em contato diretamente. O PyMongo então valida o certificado em relação à resposta do OCSP. Se a CA não tiver revogado o certificado, a negociação TLS continuará, mesmo que a resposta OCSP seja inválida ou malformada.

Para impedir que o PyMongo entre em contato com o endpoint OCSP, defina a opção de conexão tlsDisableOCSPEndpointCheck como True. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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)

Observação

Mesmo que a opção tlsDisableOCSPEndpointCheck esteja definida como True, o PyMongo ainda verificará qualquer resposta OCSP grampeada no certificado de um servidor.

Em vez de usar o OCSP, você pode instruir o PyMongo a verificar o certificado do servidor em relação a uma Lista de revogação de certificados (CRL) publicada pela CA. Para fazer isso, use a opção de conexão tlsCRLFile para especificar o caminho para um arquivo .pem ou .der da CA. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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)

Observação

Você não pode usar um CRL e um OCSP no mesmo handshake TLS.

Algumas implementações do MongoDB exigem que cada aplicativo de conexão apresente um certificado de cliente que comprove sua identidade. Para especificar o certificado do cliente para o PyMongo apresentar, defina a opção tlsCertificateKeyFile para o caminho do arquivo .pem que contém seu certificado e chave privada. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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

Seu certificado de cliente e chave privada devem estar no mesmo arquivo .pem . Se estiverem armazenados em arquivos diferentes, você deverá concatená-los. O exemplo a seguir mostra como concatenar um arquivo de chave e um arquivo de certificado em um terceiro arquivo chamado combined.pem em um sistema Unix:

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

Se a chave privada em seu arquivo de certificado estiver criptografada, você deverá fornecer uma senha. Para fazer isso, use a opção de conexão tlsCertificateKeyFilePassword para especificar a senha ou frase secreta para a chave privada criptografada. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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)

Quando o TLS está habilitado, o PyMongo verifica automaticamente o certificado apresentado pelo servidor. Ao testar seu código, você pode desativar essa verificação. Isso é conhecido como TLS inseguro.

Quando o TLS inseguro está habilitado, o PyMongo exige apenas que o servidor apresente um certificado X.509 . O driver aceita um certificado mesmo que alguma das seguintes afirmações seja verdadeira:

  • O nome do host do servidor e o nome do assunto (ou nome alternativo do assunto) no certificado não correspondem.

  • O certificado expirou ou ainda não é válido.

  • O certificado não tem um certificado raiz confiável na cadeia.

  • A finalidade do certificado não é válida para identificação do servidor.

Observação

Mesmo quando o TLS inseguro está habilitado, a comunicação entre o cliente e o servidor é criptografada com TLS.

Para habilitar o TLS inseguro, defina a opção de conexão tlsInsecure como True. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient ou por meio de um parâmetro em sua connection string.

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 desabilitar somente a validação do certificado, defina a opção tlsAllowInvalidCertificates como True e defina a opção tlsInsecure como False ou omita-a:

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 desabilitar somente a verificação do nome de host, configure a opção tlsAllowInvalidHostnames para True e configure a opção tlsInsecure para False ou omita:

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)

Aviso

Não use em produção

Sempre defina as opções tlsInsecure, tlsAllowInvalidCertificates e tlsAllowInvalidHostnames como False em produção.

Definir qualquer uma dessas opções como True em um ambiente de produção torna seu aplicativo desprotegido e potencialmente vulnerável a certificados expirados e a processos externos que se apresentam como instâncias de cliente válidas.

Uma mensagem de erro semelhante à seguinte significa que o OpenSSL não conseguiu verificar o certificado do servidor:

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

Isso geralmente acontece porque o OpenSSL não consegue acessar os certificados raiz do sistema ou porque os certificados estão desatualizados.

Se você usar Linux, certifique-se de ter as atualizações de certificado raiz mais recentes instaladas do seu fornecedor de Linux.

Se você usa macOS e se está executando o Python v3.7 ou posterior baixado de python.org, execute o seguinte comando para instalar certificados raiz:

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

Dica

Para obter mais informações sobre este problema, consulte Problema do 29065 Python.

Se você usar o embedded-pypy, talvez seja necessário definir uma variável de ambiente para informar ao OpenSSL onde encontrar certificados raiz. O seguinte exemplo de código mostra como instalar o módulo certifi do PyPi e exportar a SSL_CERT_FILE variável de ambiente:

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

Dica

Para obter mais informações sobre esse problema, consulte problema 15 portátil-pypy.

Uma mensagem de erro semelhante à seguinte significa que a versão OpenSSL usada pelo Python não suporta um protocolo TLS novo o suficiente para se conectar ao servidor:

[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version

As melhores práticas do setor recomendam, e algumas regulamentações exigem, que os protocolos TLS mais antigos sejam desabilitados em algumas implantações do MongoDB. Algumas implantações podem desativar o TLS 1.0, enquanto outras podem desativar o TLS 1.0 e o TLS 1.1.

Nenhuma alteração no aplicativo é necessária para que o PyMongo use as versões mais recentes do TLS, mas algumas versões do sistema operacional podem não fornecer uma versão do OpenSSL nova o suficiente para habilitá-las.

Se você usa macOS v10.12 (High Sierra) ou anterior, instale o Python a partir de python.org, homebrew, macports ou uma fonte semelhante.

Se você usa Linux ou outro Unix não macOS, use o seguinte comando para verificar sua versão do OpenSSL:

$ openssl version

Se o comando anterior mostrar um número de versão inferior a 1.0.1, suporte para TLS 1.1 ou mais recente não está disponível. Atualize para uma versão mais recente ou entre em contato com o fornecedor do sistema operacional para obter uma solução.

Para verificar a versão TLS do seu interpretador Python, instale o módulo requests e execute o seguinte código:

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

Você deve ver TLS 1.1 ou posterior.

Uma mensagem de erro semelhante à seguinte significa que a verificação de revogação do certificado falhou:

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

Para obter mais detalhes, consulte a seção OCSP deste guia.

Ao usar o Python v3.10 ou posterior com versões do MongoDB anteriores à v4.0, você pode ver erros semelhantes às seguintes mensagens:

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)

Os registros do MongoDB Server também podem mostrar o seguinte erro:

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

As alterações feitas no módulo ssl no Python v3.10 podem causar incompatibilidades com versões do MongoDB anteriores4 à0 v.. Para resolver esse problema, tente uma ou mais das seguintes etapas:

  • Faça downgrade do Python para a3.9 ou anterior

  • Atualize o MongoDB Server para v4.2 ou posterior

  • Instalar o PyMongo com a opção OCSP , que depende do PyOpenSSL

Ao usar o OpenSSL v3 ou posterior, você poderá ver um erro semelhante à seguinte mensagem:

[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled

Esses tipos de erros ocorrem devido a proxies SSL desatualizados ou com erros que impõem erroneamente a renegociação do TLS legado .

Para resolver esse problema, execute as seguintes etapas:

1

Execute o seguinte comando para garantir que você tenha o OpenSSL vv3.0.4 ou posterior instalado:

openssl version
2

Crie um arquivo de configuração que inclua a opção UnsafeLegacyServerConnect. O exemplo seguinte mostra como configurar a opção UnsafeLegacyServerConnect:

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

Execute o Python enquanto configura a variável de ambiente do OPENSSL_CONF para utilizar o arquivo de configuração OpenSSL que você acabou de criar:

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

Importante

Como a UnsafeLegacyServerConnect configuração da opção tem implicações de segurança, use esta solução alternativa como último recurso para solucionar unsafe legacy renegotiation disabled erros.

Para saber mais sobre como configurar o TLS para o PyMongo, consulte a seguinte documentação da API:

Voltar

Criptografia em execução