HTTPS e SSL3_GET_SERVER_CERTIFICATE: falha na verificação do certificado, CA está OK

208

Estou usando o XAMPP para desenvolvimento. Recentemente, atualizei minha instalação do xampp de uma versão antiga para a 1.7.3.

Agora, quando enrolado sites habilitados para HTTPS, recebo a seguinte exceção

Erro fatal: exceção não capturada 'RequestCore_Exception' com a mensagem 'recurso cURL: ID do recurso # 55; Erro cURL: problema no certificado SSL, verifique se o certificado da CA está OK. Detalhes: erro: 14090086: rotinas SSL: SSL3_GET_SERVER_CERTIFICATE: falha na verificação do certificado (60) '

Todos sugerem o uso de algumas opções específicas de curl do código PHP para corrigir esse problema. Eu acho que não deveria ser assim. Porque não tive nenhum problema com a minha versão antiga do XAMPP e só aconteceu depois de instalar a nova versão.

Preciso de ajuda para descobrir quais configurações são alteradas na minha instalação do PHP, Apache etc. podem corrigir esse problema.

Josnidhin
fonte

Respostas:

145

o curl costumava incluir uma lista de CAs aceitas, mas não agrupa mais QUALQUER certificado de CA. Portanto, por padrão, rejeitará todos os certificados SSL como não verificáveis.

Você precisará obter o certificado da CA e apontar ondulações para ele. Mais detalhes em Detalhes do cURLS sobre certificados SSL do servidor .

Marc B
fonte
4
A onda está acontecendo na biblioteca php de serviços web da Amazon. Não entendi como corrigi-lo sem editar o código da biblioteca.
21711 Josnidhin
41
Em seguida, desative a verificação do certificado ( CURLOPT_SSL_VERIFYPEER-> false). Você pode adicionar o certificado de CA do site com o qual está tentando fazer SSL ou desabilitar a verificação da CA. Essas são as duas únicas opções disponíveis.
Marc B
78
Apenas fyi - configuração CURLOPT_SSL_VERIFYPEERpara falseanula o propósito de usar SSL.
Até
13
@ Até que não derrote metade da finalidade do SSL? Você ainda tem privacidade entre você e seu colega: você simplesmente não tem autenticidade.
Mark Fox
10
sem autenticidade, qual é o sentido de criptografar os dados que você está enviando? Se você tiver sido MITMed seguida, os dados é comprometida de qualquer maneira
hdgarrood
290

É um problema bastante comum no Windows. Você precisa apenas definir cacert.pemcomo curl.cainfo.

Desde o PHP 5.3.7, você pode fazer:

  1. faça o download de https://curl.haxx.se/ca/cacert.pem e salve-o em algum lugar.
  2. atualização php.ini- add curl.cainfo = "PATH_TO / cacert.pem"

Caso contrário, você precisará fazer o seguinte para cada recurso cURL:

curl_setopt ($ch, CURLOPT_CAINFO, "PATH_TO/cacert.pem");
Артур Курицын
fonte
2
Isso funcionou para mim no XAMPP no OS X. Foi corrigido um problema em que um plugin do Wordpress não era atualizado devido à impossibilidade de localizar um certificado local.
Jonathan Nicol
8
Para qualquer outra pessoa que tente resolver esse problema no Windows usando o Apache, tive que definir o caminho completo (por exemplo, C: \ PATH_TO \ cacert.pem) no meu código PHP. No IIS, o caminho relativo parecia funcionar bem.
http203
Se o cacert.pem estiver no mesmo diretório, então curl_setopt ($ ch, CURLOPT_CAINFO, dirname ( FILE ). '/Cacert.pem'); funcionará
mujaffars
7
Ao usar o WampServer com 2., você deve adicionar a variável a dois php.iniarquivos separados . Veja stackoverflow.com/a/25706713/1101095
Nate
O que é intrigante / irônico é que você pode fazer o download do curl.haxx.se/ca/cacert.pem através de HTTPS sem especificar opções adicionais. O certificado do curl.haxx.se foi copiado para o próprio curl?
22416 qbolec
84

Aviso: isso pode apresentar problemas de segurança contra os quais o SSL foi projetado para proteger, tornando toda a sua base de código insegura. Isso vai contra todas as práticas recomendadas.

Mas uma correção realmente simples que funcionou para mim foi chamar:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

antes de ligar para:

curl_exec():

no arquivo php.

Acredito que isso desabilite toda a verificação de certificados SSL.

Chris Dutrow
fonte
65
... e desativando a verificação dos certificados, você deixa a porta aberta para possíveis ataques MITM, contra os quais o SSL / TLS visa proteger. NÃO FAÇA ISTO!
Bruno
12
Sim. Eu deveria ter chamado mais atenção para isso na resposta. Faça isso apenas se você não estiver trabalhando em algo importante. Eu o uso no host local para acessar sites que eu pessoalmente programei.
Chris Dutrow
3
Voto negativo de mim. Esta é uma correção suja para que seu código funcione, mas não uma solução. A resposta fornecida por Артур Курицын é muito melhor.
precisa
2
@Bruno Esta é a solução perfeita, para scripts auxiliares, testes, aplicativos confiáveis, intranet, ..... Todo mundo que conhece POUCO SOBRE SSL, sabe em quais casos a validação de certificado pode ser ignorada. Portanto, todos os comentários 'inteligentes' sobre esta resposta e coisas como 'NÃO FAÇA ISSO' são apenas um absurdo!
Kenyakorn Ketsombut 13/03/2015
5
... " Todo mundo que conhece UM POUCO sobre SSL [...] " ... e você ficaria surpreso com quantas pessoas nem se importam em saber um pouco sobre o básico do SSL / TLS e estão chegando. aqui para copiar / colar uma correção rápida para a mensagem de erro.
de Bruno
53

Fonte: http://ademar.name/blog/2006/04/curl-ssl-certificate-problem-v.html

Problema no certificado SSL: verifique se o certificado da CA está OK

07 de abril de 2006

Ao abrir um URL seguro com o Curl, você pode receber o seguinte erro:

Problema no certificado SSL, verifique se o certificado da CA está OK

Vou explicar por que o erro e o que você deve fazer sobre isso.

A maneira mais fácil de se livrar do erro seria adicionar as duas linhas a seguir ao seu script. Esta solução apresenta um risco de segurança.

//WARNING: this would prevent curl from detecting a 'man in the middle' attack
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); 

Vamos ver o que esses dois parâmetros fazem. Citando o manual.

CURLOPT_SSL_VERIFYHOST : 1 para verificar a existência de um nome comum no certificado de mesmo nível SSL. 2 para verificar a existência de um nome comum e também verificar se ele corresponde ao nome do host fornecido.

CURLOPT_SSL_VERIFYPEER : FALSE para impedir que CURL verifique o certificado do par. Certificados alternativos para verificação podem ser especificados com a opção CURLOPT_CAINFO ou um diretório de certificado pode ser especificado com a opção CURLOPT_CAPATH. Talvez CURLOPT_SSL_VERIFYHOST também precise ser TRUE ou FALSE se CURLOPT_SSL_VERIFYPEER estiver desativado (o padrão é 2). Definir CURLOPT_SSL_VERIFYHOST como 2 (este é o valor padrão) garantirá que o certificado que está sendo apresentado a você tenha um 'nome comum' correspondente ao URN que você está usando para acessar o recurso remoto. Esta é uma verificação saudável, mas não garante que o seu programa não está sendo enganado.

Digite o 'homem do meio'

Seu programa pode ser enganado ao conversar com outro servidor. Isso pode ser conseguido através de vários mecanismos, como DNS ou envenenamento por arp (esta é uma história para outro dia). O invasor também pode autoassinar um certificado com o mesmo 'nome comum' que seu programa está esperando. A comunicação ainda seria criptografada, mas você revelaria seus segredos a um impostor. Esse tipo de ataque é chamado de 'homem do meio'

Derrotar o 'homem do meio'

Bem, precisamos verificar se o certificado que está sendo apresentado para nós é bom de verdade. Fazemos isso comparando-o com um certificado em que razoavelmente * confiamos.

Se o recurso remoto estiver protegido por um certificado emitido por uma das principais autoridades de certificação como Verisign, GeoTrust et al, você poderá comparar com segurança o pacote de certificados de autoridade de certificação da Mozilla, que pode obter em http://curl.haxx.se/docs/caextract .html

Salve o arquivo cacert.pemem algum lugar do seu servidor e defina as seguintes opções no seu script.

curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, TRUE); 
curl_setopt ($ch, CURLOPT_CAINFO, "pathto/cacert.pem");

para Tudo acima Informações de crédito Vá para: http://ademar.name/blog/2006/04/curl-ssl-certificate-problem-v.html

Deepak Oberoi
fonte
38
Geralmente, é educado creditar a fonte de suas informações e citar apenas certas partes relevantes para a pergunta, em vez de simplesmente copiar e colar aqui!
Dan Herd
1
Desculpe, eu estive fora, sim, eu apregoo Dan para isso e atualizei o Post
Deepak Oberoi
6
Pelo menos Deepak fez um esforço para pesquisá-lo. @danherd Então, Danherd, você acabou de fazer a pesquisa para descobrir que ele pegou o código de algum lugar? Qual era o direito de atribuição deste código? Em vez de desperdiçar seu tempo para encontrar os erros de outra pessoa, tente ajudar alguém sozinho. Não lute, compartilhe!
GTodorov
17

As soluções acima são ótimas, mas se você estiver usando o WampServer, poderá achar que a configuração da curl.cainfovariável php.ininão funciona.

Acabei encontrando o WampServer com dois php.iniarquivos:

C:\wamp\bin\apache\Apachex.x.x\bin
C:\wamp\bin\php\phpx.x.xx

O primeiro é aparentemente usado para quando arquivos PHP são chamados por meio de um navegador da Web, enquanto o segundo é usado quando um comando é chamado por meio da linha de comando ou shell_exec().

TL; DR

Se estiver usando o WampServer, você deve adicionar a curl.cainfolinha aos dois php.ini arquivos.

Nate
fonte
6

Pelo amor de tudo o que é santo ...

No meu caso, eu tive que definir o openssl.cafile variável de configuração PHP para o caminho do arquivo PEM.

Confio que é verdade que existem muitos sistemas em que a configuração curl.cainfona configuração do PHP é exatamente o que é necessário, mas no ambiente com o qual estou trabalhando, que é o eboraas / laravel docker, que usa Debian 8 (jessie) e PHP 5.6, definir essa variável não funcionou.

Percebi que a saída de php -inão mencionou nada sobre essa configuração específica, mas havia algumas linhas openssl. Há uma opção openssl.capathe openssl.cafile, mas apenas definir a segunda opção permitida via PHP para finalmente ficar bem com os URLs HTTPS.

Spencer Williams
fonte
Obrigado! Definir o curl.cainfo também não funcionou para mim, mas definir o openssl.cafile funcionou! Estou no Windows 7 com XAMPP e PHP 7.1.1.
knezmilos
@knezmilos, como você definiu o openssl.cafile? onde você baixou e como ativá-lo?
Krypton #
Bem, já faz um tempo, mas acho que é algo assim: curl.cainfo = "C: \ xampp \ cacert \ cacert.pem" e openssl.cafile = "C: \ xampp \ cacert \ cacert.pem" no php. ini, enquanto acho que obtive o arquivo pem de uma das respostas aqui.
Knezmilos
1
"Pelo amor de tudo o que é santo ..." de fato. Isso funcionou para a minha instalação do Ubuntu 18.08 / Apache / Php7.2. Se o erro onda está apontando para o arquivo correto, então ele certamente é culpa openssls
JTG
4

Às vezes, se o aplicativo que você tentar entrar em contato tiver certificados autoassinados, o cacert.pem normal em http://curl.haxx.se/ca/cacert.pem não resolverá o problema.

Se você tiver certeza do URL do terminal em serviço, acesse-o pelo navegador, salve o certificado manualmente no formato "Certificado X 509 com cadeia (PEM)". Aponte este arquivo de certificado com o

curl_setopt ($ch, CURLOPT_CAINFO, "pathto/{downloaded certificate chain file}");   
madRai
fonte
4

Eu tenho o mesmo erro no Amazon AMI linux.

Resolvi definindo curl.cainfo em /etc/php.d/curl.ini

https://gist.github.com/reinaldomendes/97fb2ce8a606ec813c4b

Adição outubro 2018

No Amazon Linux v1, edite este arquivo

vi /etc/php.d/20-curl.ini

Para adicionar esta linha

curl.cainfo="/etc/ssl/certs/ca-bundle.crt"
Reinaldo Mendes
fonte
Perfeito, obrigado! Atualizei a pergunta para adicionar exatamente o que fiz e resolvi o problema para mim, em vez de criar outra resposta.
Tim
3

Ao definir as opções de curvatura para CURLOPT_CAINFO, lembre-se de usar aspas simples, usar aspas duplas causará apenas outro erro. Portanto, sua opção deve se parecer com:

curl_setopt ($ch, CURLOPT_CAINFO, 'c:\wamp\www\mywebfolder\cacert.pem');

Além disso, no seu arquivo php.ini, a configuração deve ser escrita como: (observe minhas aspas duplas)

curl.cainfo = "C:\wamp\www\mywebfolder"

Coloquei diretamente abaixo da linha que diz o seguinte: extension=php_curl.dll

(Apenas para fins de organização, você pode colocá-lo em qualquer lugar dentro do seu php.ini, basta colocá-lo perto de outra referência de ondulação; portanto, quando procuro usando a palavra-chave ondulação, posso encontrar as duas referências de ondulação em uma área.)

LOwens1931
fonte
1
Espero php.ini deve apontar para o arquivo pem vez de sua pasta pai
dejjub-AIS
2

Acabei aqui ao tentar obter o GuzzleHttp (php + apache no Mac) para obter uma página em www.googleapis.com.

Aqui estava minha solução final, caso isso ajude alguém.

Examine a cadeia de certificados para qualquer domínio que esteja fornecendo esse erro. Para mim, foi googleapis.com

openssl s_client -host www.googleapis.com -port 443

Você receberá algo como isto:

Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.googleapis.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority

Nota: Eu capturei isso depois de corrigir o problema. A saída da sua cadeia pode parecer diferente.

Então você precisa olhar para os certificados permitidos no php. Execute phpinfo () em uma página.

<?php echo phpinfo();

Em seguida, procure o arquivo de certificado carregado na saída da página:

openssl.cafile  /usr/local/php5/ssl/certs/cacert.pem

Esse é o arquivo que você precisará corrigir adicionando os certificados corretos.

sudo nano /usr/local/php5/ssl/certs/cacert.pem

Basicamente, você precisa anexar as "assinaturas" corretas do certificado ao final deste arquivo.

Você pode encontrar alguns deles aqui: talvez seja necessário pesquisar no google / outros na cadeia, se você precisar deles.

Eles se parecem com isso:

imagem de certificado de exemplo

( Nota: Esta é uma imagem para que as pessoas não copiem / colem simplesmente certificados do stackoverflow )

Quando os certificados corretos estiverem nesse arquivo, reinicie o apache e teste.

TrophyGeek
fonte
0

Você pode tentar reinstalar o ca-certificatespacote ou permitir explicitamente o certificado em questão, conforme descrito aqui .

local
fonte
-5

A solução é muito simples! Coloque esta linha antes curl_exec:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

Para mim funciona.

Zsolt Boszormenyi
fonte
7
Nunca, jamais desative a verificação por pares, a menos que você não se importe se os dados estiverem comprometidos em trânsito.
precisa saber é o seguinte
Acordado. Se você deseja um aplicativo seguro, precisa da verificação por pares.
22814
2
"Nunca desative a verificação por pares", a menos que você queira a funcionalidade padrão do navegador, haha. Além disso, por que isso é tão prejudicado? Esta é a única resposta que é curta, doce, ao ponto E eficaz.
23714 Adam
@AdamF FYI, os navegadores verificam o certificado de mesmo nível, por padrão, eles oferecem a opção de ignorar erros manualmente, com um aviso.
224 Bruno