Solicitações de Python lançando SSLError


348

Estou trabalhando em um script simples que envolve CAS, verificação de segurança jspring, redirecionamento etc. Gostaria de usar as solicitações python de Kenneth Reitz, porque é um ótimo trabalho! No entanto, o CAS exige a validação via SSL, por isso tenho que passar pela etapa primeiro. Eu não sei o que Python solicita está querendo? Onde esse certificado SSL deve residir?

Traceback (most recent call last):
  File "./test.py", line 24, in <module>
  response = requests.get(url1, headers=headers)
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 52, in get
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 40, in request
  File "build/bdist.linux-x86_64/egg/requests/sessions.py", line 209, in request 
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 624, in send
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 300, in _build_response
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 611, in send
requests.exceptions.SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

Você pode compartilhar mais informações do código? Parece que falta um passo.
precisa saber é o seguinte

5
Você sempre deve mencionar versões de software com as quais precisa de ajuda.
Piotr Dobrogost

Eu tenho esse problema onde eu uso o python 3.5 tornado 4.4. HTTPRequest definir o validate_cert = True, de modo que você pode configurá-lo Falso para negociá-lo
pan7an

Respostas:


460

O problema que você está tendo é causado por um certificado SSL não confiável.

Como o @dirk mencionado em um comentário anterior, a solução mais rápida é a configuração verify=False:

requests.get('https://example.com', verify=False)

Observe que isso fará com que o certificado não seja verificado. Isso exporá seu aplicativo a riscos de segurança, como ataques do tipo intermediário.

Claro, aplique julgamento. Conforme mencionado nos comentários, isso pode ser aceitável para aplicativos / scripts rápidos / descartáveis, mas realmente não deve ir para o software de produção .

Se apenas ignorar a verificação do certificado não for aceitável em seu contexto específico, considere as seguintes opções, sua melhor opção é definir o verifyparâmetro para uma sequência que seja o caminho do .pemarquivo do certificado (que você deve obter por algum tipo de segurança). significa).

Portanto, a partir da versão 2.0, o verifyparâmetro aceita os seguintes valores, com suas respectivas semânticas:

  • True: faz com que o certificado seja validado pelas autoridades de certificação confiáveis ​​da biblioteca (Nota: você pode ver quais solicitações de certificados raiz usam através da biblioteca Certifi, um banco de dados confiável de RCs extraídos de Requests: Certifi - Trust Database for Humans ).
  • False: ignora completamente a validação de certificado .
  • Caminho para um arquivo CA_BUNDLE a ser usado por solicitações para validar os certificados.

Fonte: Solicitações - Verificação de Certificados SSL

Veja também o certparâmetro no mesmo link.


11
Sim, quando usei o dotCloud no ubuntu, o mesmo "certificado de verificação falhou" saiu. Após a modificação de "orders.session (cabeçalhos = cabeçalhos, ganchos = ganchos, verifique = Falso)" em "/usr/local/lib/python2.6/dist-packages/dotcloud/client/client.py", funcionou.
diyism

2
Isso não está marcado como correto, mas posso verificar se funciona (ao contrário das respostas abaixo).
khalid13

40
@ khalid13: Um machado "funciona" como remédio para dor de cabeça (sem cabeça - sem dor de cabeça). Isso não significa que é uma boa idéia usá-lo dessa maneira. verify=Falsedesativa a verificação de certificado SSL do host.
jfs

24
@JFSebastian Honestamente, isso depende do que você está fazendo. Para minha aplicação rápida / descartável, era mais do que suficiente.
khalid13

5
@diyism fazer tal mudança sons muito inseguras ...
binki

111

Na documentação de solicitações sobre verificação SSL :

As solicitações podem verificar os certificados SSL para solicitações HTTPS, assim como um navegador da web. Para verificar o certificado SSL de um host, você pode usar o argumento de verificação:

>>> requests.get('https://kennethreitz.com', verify=True)

Se você não deseja verificar seu certificado SSL, faça verify=False


4
Bem, eu adicionei o Verifique = True, mas ainda recebi exatamente o mesmo erro. Nenhuma mudança. Algo mais deve ser necessário, mas não sei o que poderia ser.
TedBurrows

Suponho que agora mergulhei na loucura do SSL. Adicionei isso ao meu get inicial ... get (url1, cabeçalhos = cabeçalhos, cert = '/ etc / pki / tls / cert.pem', verifique = True, config = my_config) Então, agora estou recebendo esse erro. orders.exceptions.SSLError: [Erro 336265225] _ssl.c: 351: erro: 140B0009: rotinas SSL: SSL_CTX_use_PrivateKey_file: PEM lib Não tenho idéia do que isso significa.
TedBurrows

14
Basta definir verificar = False se você não quiser validar o certificado, iow se você tiver um certificado auto-assinado
Dirk

16
Se você possui um certificado autoassinado, faça o download e defina o nome do arquivo como verificar. Não há desculpa alguma para a configuração de verificar = Falso. Verifique = '/ caminho / para / cert.pem'
Matthias Urlichs

14
Desculpe Boud, eu precisava votar negativamente esta resposta, pois as solicitações não tratam as solicitações HTTPS "como um navegador da web". Se a cadeia de confiança SSL completa (incluindo certificados intermediários) não for declarada em um servidor e exigir um download extra de certificado, você receberá o erro de verificação SSL acima. Os navegadores da Web farão o download extra e não sinalizarão nenhum erro de certificado. Essa é uma maneira pela qual um navegador da web e solicitações diferem. Há outros. Solicitações faz alguma verificação, mas não é tão bom quanto um navegador.
Louis Cremen

53

O nome do arquivo da CA a ser usado pode ser transmitido por verify:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

Se você usar verify=True, requestsusará seu próprio conjunto de CA que pode não ter uma CA que assinou o certificado do servidor.


12
@ 9emE0iL18gxCqLT: por que você acha que todos os sistemas usam o caminho que você forneceu? requestspode ser empacotado para sua distribuição. Corra python -mrequests.certspara descobrir para onde ele aponta.
jfs

3
Se o pacote cacert da solicitação Python estiver desatualizado, como atualizá-lo?
CMCDragonkai

5
Você não deve usar isso cacert.pemde curl. Ele contém muitos certificados revogados. Confira Certifi (que solicita usos): certifi.io
Kenneth Reitz

3
@KennethReitz: 1 - o que o Requests usa falha no OP (caso contrário não havia a pergunta) 2 - os cacert.pemcertificados de CA são extraídos do Mozilla (por cURL) - é apenas um exemplo (se a lista de CA usada por uma web popular -browser não pode ser usado como exemplo, então não sei o que pode ser) - o ponto da resposta em que você pode passar seu próprio arquivo CA se a lista padrão falhar.
JFS

Você pode fazer isso e usar certificados de cliente ao mesmo tempo? Estou tendo problemas com isso.
user1156544

42

$ pip install -U requests[security]

  • Testado em Python 2.7.6 @ Ubuntu 14.04.4 LTS
  • Testado em Python 2.7.5 @ MacOSX 10.9.5 (Mavericks)

Quando esta pergunta foi aberta (2012-05), a versão Requests era 0.13.1. Na versão 2.4.1 (2014-09), os extras de "segurança" foram introduzidos, usandocertifi pacote, se disponível.

No momento (2016-09), a versão principal é a 2.11.1, que funciona bem sem verify=False . Não há necessidade de usar requests.get(url, verify=False), se instalado com requests[security]extras.


7
corrigido por pip install -U requests[security] --no-cacheduas vezes epip install certifi==2015.04.28
Aamir Abro

@alanjds E se eu quiser configurar o python para confiar em algum certificado SSL ou desativar a verificação de certificado, mas globalmente no ambiente, sem editar o código-fonte? Por exemplo, se eu baixar os utilitários Python existentes (por exemplo, a AWS CLI) e desejar confiar em certs ou ignorar a validação de certificado para essas ferramentas?
Howiecamp

@Howiecamp então você pode ir resposta via jf-sebastian, eu acho: stackoverflow.com/a/12865159/798575
alanjds

@alanjds Mas a resposta dele não pressupõe que eu esteja escrevendo o código e / ou tenha acesso ao código? Estou procurando implementar isso no nível do ambiente.
Howiecamp

3
que pip install --upgrade pipantes de instalar o pacote de segurança pedidos para evitar outros erros
Vincent Claes

40

Encontrei o mesmo problema e o certificado ssl verifica o problema com falha ao usar o aws boto3. Ao revisar o código boto3, descobri que o REQUESTS_CA_BUNDLEnão está definido. Por isso, corrigi os dois problemas configurando-o manualmente:

from boto3.session import Session
import os

# debian
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(
    '/etc/ssl/certs/',
    'ca-certificates.crt')
# centos
#   'ca-bundle.crt')

Para o aws-cli, acho que a configuração de REQUESTS_CA_BUNDLE ~/.bashrccorrigirá esse problema (não testado porque o meu aws-cli funciona sem ele).

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE

2
Isso resolveu o meu problema! Eu estava usando o Charles Proxy no Mac para depurar uma biblioteca que fazia chamadas JSON para APIs HTTPS. Instalei o certificado Charless conforme especificado, adicionei-o ao chaveiro, mas o Python continuava falhando com: SSLError: ("handshake ruim: erro ([('rotinas SSL', 'ssl3 rotinas', 'ssl3_get_server_certificate', 'verificação de certificado com falha')],)") ,) Para corrigir isso, acabei seguindo seu conselho sobre como adicionar REQUESTS_CA_BUNDLE e exportar o certificado Charles do meu chaveiro como um arquivo .pem. Agora funciona!
mallyvai

Graças, o mesmo problema foi com abriu Fiddler
user565447

@ user565447 Estou tentando fazer isso funcionar com o Fiddler agora. A configuração de REQUESTS_CA_BUNDLE como certificado do Fiddler deve funcionar?
Howiecamp

19

Caso você tenha uma biblioteca que depende requestse não possa modificar o caminho de verificação (como em pyvmomi), será necessário encontrar as cacert.pemsolicitações incluídas no pacote e anexar sua CA ali. Aqui está uma abordagem genérica para encontrar o cacert.pemlocal:

janelas

C:\>python -c "import requests; print requests.certs.where()"
c:\Python27\lib\site-packages\requests-2.8.1-py2.7.egg\requests\cacert.pem

linux

#  (py2.7.5,requests 2.7.0, verify not enforced)
root@host:~/# python -c "import requests; print requests.certs.where()"
/usr/lib/python2.7/dist-packages/certifi/cacert.pem

#  (py2.7.10, verify enforced)
root@host:~/# python -c "import requests; print requests.certs.where()"
/usr/local/lib/python2.7/dist-packages/requests/cacert.pem

btw. @ orders-devs, empacotar seus próprios cacerts com request é muito, muito chato ... especialmente o fato de você não parecer usar o sistema ca store primeiro e isso não estar documentado em nenhum lugar.

atualizar

em situações em que você está usando uma biblioteca e não tem controle sobre o local do pacote configurável, você também pode definir explicitamente o local do pacote configurável como o pacote configurável para todo o host:

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c "import requests; requests.get('https://somesite.com';)"

Cem vezes isso: chave é incapacidade de modificar o verifycaminho.
ghukill

E se você estiver usando um certificado autoassinado? Qual seria a CA nesse caso?
user1114

Atualização minúscula - para python 3.6, deve haver parênteses para o comando print - python -c "solicitações de importação; print (
orders.certs.where

15

Eu enfrento o mesmo problema usando o gspread e esses comandos funcionam para mim:

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28

Isso fez por mim. Obrigado :)
alex-mcleod

4
Isso tem a desvantagem de reinstalar certificados potencialmente revogados / não confiáveis ​​da versão mais antiga do certifi, NÃO recomendado.
dragon788

Se por algum motivo você é forçado a ficar com uma versão inicial do Python 2.7, degradando certifi é a única abordagem que funcionou para mim
seans

15

Se você deseja remover os avisos, use o código abaixo.

import urllib3

urllib3.disable_warnings()

e verify=Falsecom request.getou postmétodo


12

Eu encontrei uma abordagem específica para resolver um problema semelhante. A idéia é apontar o arquivo cacert armazenado no sistema e usado por outros aplicativos baseados em SSL.

No Debian (não tenho certeza se é o mesmo em outras distribuições), os arquivos de certificado (.pem) são armazenados em /etc/ssl/certs/Então, este é o código que funciona para mim:

import requests
verify='/etc/ssl/certs/cacert.org.pem'
response = requests.get('https://lists.cacert.org', verify=verify)

Para adivinhar qual pemarquivo escolher, procurei o URL e verifiquei qual autoridade de certificação (CA) gerou o certificado.

EDIT: se você não pode editar o código (porque está executando um terceiro aplicativo), pode tentar adicionar o pemcertificado diretamente /usr/local/lib/python2.7/dist-packages/requests/cacert.pem(por exemplo, copiá-lo para o final do arquivo).


2
Post relacionado para depuração CA_BUNDLE usado pelo python.
CHK

Que tal substituir /usr/local/lib/python2.7/dist-packages/requests/cacert.pempor um link simbólico para a loja do SO?
CMCDragonkai

8

Se você não se preocupa com o certificado, basta usar verify=False.

import requests

url = "Write your url here"

returnResponse = requests.get(url, verify=False)

7

Após horas de depuração, eu só conseguia fazer isso funcionar usando os seguintes pacotes:

requests[security]==2.7.0  # not 2.18.1
cryptography==1.9  # not 2.0

usando OpenSSL 1.0.2g 1 Mar 2016

Sem esses pacotes verify=Falsenão estava funcionando.

Espero que isso ajude alguém.


5

Eu tive o mesmo problema. Acontece que eu não havia instalado o certificado intermediário no meu servidor (basta anexá-lo à parte inferior do seu certificado, como mostrado abaixo).

https://www.digicert.com/ssl-support/pem-ssl-creation.htm

Verifique se você tem o pacote ca-certificates instalado:

sudo apt-get install ca-certificates

A atualização do horário também pode resolver isso:

sudo apt-get install ntpdate
sudo ntpdate -u ntp.ubuntu.com

Se você estiver usando um certificado autoassinado, provavelmente precisará adicioná-lo ao seu sistema manualmente.


Note, isso se aplica apenas às instalações de Solicitações via apt-get, que são modificadas pelo Debian / Ubuntu para usar certs do sistema. Solicita navios adequados com a sua própria, cuidadosamente curadoria, CA Bundle: certifi.io
Kenneth Reitz

A CA raiz não deveria ser suficiente? Por que você precisa dos intermediários?
Timmy

5

Se as chamadas de solicitação estão enterradas em algum lugar profundo do código e você não deseja instalar o certificado do servidor, apenas para fins de depuração , é possível monitorar solicitações de monkeypatch:

import requests.api
import warnings


def requestspatch(method, url, **kwargs):
    kwargs['verify'] = False
    return _origcall(method, url, **kwargs)

_origcall = requests.api.request
requests.api.request = requestspatch
warnings.warn('Patched requests: SSL verification disabled!')

Nunca use em produção!


4

Acho que é muito tarde para a festa, mas eu queria colar a correção para outros andarilhos como eu! Então, o seguinte funcionou para mim no Python 3.7.x

Digite o seguinte no seu terminal

pip install --upgrade certifi      # hold your breath..

Tente executar seu script / pedidos novamente e veja se funciona (tenho certeza de que ainda não será corrigido!). Se não funcionou, tente executar o seguinte comando no terminal diretamente

open /Applications/Python\ 3.6/Install\ Certificates.command  # please replace 3.6 here with your suitable python version

3

Eu lutei contra esse problema por HOURS.

Eu tentei atualizar solicitações. Então eu atualizei certifi. Apontei verificar para certifi.where () (o código faz isso por padrão de qualquer maneira). Nada funcionou.

Finalmente, atualizei minha versão do python para o python 2.7.11. Eu estava no Python 2.7.5, que tinha algumas incompatibilidades com a maneira como os certificados são verificados. Depois que eu atualizei o Python (e várias outras dependências), ele começou a funcionar.


Se você atualizou o OpenSSL para uma versão> 1.0.1, provavelmente esse foi o problema. Veja minha resposta abaixo. stackoverflow.com/a/44543047/1413201
Tim Ludwinski

Passar do Python 2.7.9 para 2.7.10 corrigiu isso para mim.
crazystick

3

Isso é semelhante à resposta de @ rafael-almeida, mas quero ressaltar que, a partir das solicitações 2.11+, não há 3 valores que verifypossam ser aceitos, na verdade existem 4:

  • True: valida contra CAs confiáveis ​​internas das solicitações.
  • False: ignora completamente a validação de certificado . (Não recomendado)
  • Caminho para um arquivo CA_BUNDLE. solicitações usarão isso para validar os certificados do servidor.
  • Caminho para um diretório que contém arquivos de certificado público. solicitações usarão isso para validar os certificados do servidor.

O restante da minha resposta é sobre o nº 4, como usar um diretório que contém certificados para validar:

Obtenha os certificados públicos necessários e coloque-os em um diretório.

A rigor, você provavelmente "deve" usar um método fora de banda para obter os certificados, mas também pode baixá-los usando qualquer navegador.

Se o servidor usar uma cadeia de certificados, não deixe de obter todos os certificados da cadeia.

De acordo com a documentação das solicitações, o diretório que contém os certificados deve primeiro ser processado com o utilitário "rehash" ( openssl rehash).

(Isso requer o openssl 1.1.1+, e nem todas as implementações do Windows openssl suportam rehash. Se openssl rehashnão funcionar, você pode tentar executar o script rehash ruby ​​em https://github.com/ruby/openssl/blob/master /sample/c_rehash.rb , embora eu não tenha tentado isso.)

Eu tive alguns problemas para obter solicitações para reconhecer meus certificados, mas depois que usei o openssl x509 -outform PEMcomando para converter o certs para o .pemformato Base64 , tudo funcionou perfeitamente.

Você também pode fazer uma rehashing preguiçosa:

try:
    # As long as the certificates in the certs directory are in the OS's certificate store, `verify=True` is fine.
    return requests.get(url, auth=auth, verify=True)
except requests.exceptions.SSLError:
    subprocess.run(f"openssl rehash -compat -v my_certs_dir", shell=True, check=True)
    return requests.get(url, auth=auth, verify="my_certs_dir")

2

Atualmente, há um problema no módulo de solicitações que está causando esse erro, presente nas v2.6.2 a v2.12.4 (ATOW): https://github.com/kennethreitz/requests/issues/2573

A solução alternativa para esse problema está adicionando a seguinte linha: requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'


FWIW, ainda está presente com solicitações == 2.13.0. A solução acima corrige ainda.
Tamás Szelei

1

Conforme mencionado por @Rafael Almeida, o problema que você está tendo é causado por um certificado SSL não confiável. No meu caso, o certificado SSL não era confiável pelo meu servidor. Para contornar isso sem comprometer a segurança, baixei o certificado e o instalei no servidor (simplesmente clicando duas vezes no arquivo .crt e depois em Instalar certificado ...).


0

Não é possível adicionar opções se as solicitações estiverem sendo chamadas de outro pacote. Nesse caso, adicionar certificados ao pacote cacert é o caminho direto, por exemplo, tive que adicionar "CA do servidor intermediário primário da classe 1 do StartCom", para o qual baixei o certificado raiz no StartComClass1.pem. dado que meu virtualenv se chama caldav, adicionei o certificado com:

cat StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/pip/_vendor/requests/cacert.pem
cat temp/StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/requests/cacert.pem

um desses pode ser suficiente, eu não verifiquei


0

Eu estava tendo um problema semelhante ou o mesmo de validação de certificação. Eu li que as versões do OpenSSL menores que 1.0.2, cujas solicitações dependem, às vezes, têm problemas para validar certificados fortes (veja aqui ). O CentOS 7 parece usar o 1.0.1e, que parece ter o problema.

Eu não tinha certeza de como resolver esse problema no CentOS, então decidi permitir certificados CA 1024bit mais fracos.

import certifi # This should be already installed as a dependency of 'requests'
requests.get("https://example.com", verify=certifi.old_where())

Eu uso um Python 2.7.10 instalado pelo ArcGIS e não há nenhum módulo de certificação instalado. O módulo de pedidos instalado está na versão 2.11.1.
Lucas

0

Eu tive que atualizar do Python 3.4.0 para 3.4.6

pyenv virtualenv 3.4.6 myvenv
pyenv activate myvenv
pip install -r requirements.txt

0

No meu caso, o motivo foi bastante trivial.

Eu sabia que a verificação SSL funcionara até alguns dias antes e estava realmente trabalhando em uma máquina diferente.

Minha próxima etapa foi comparar o conteúdo e o tamanho do certificado entre a máquina em que a verificação estava funcionando e a máquina em que não estava.

Isso me levou a determinar rapidamente que o certificado na máquina de trabalho 'incorretamente' não era bom e, depois que o substituí pelo certificado 'bom', tudo estava bem.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.