Não foi possível verificar a assinatura da folha

142

Estou usando o node.js request.js para acessar uma API. Estou recebendo este erro

[Erro: UNABLE_TO_VERIFY_LEAF_SIGNATURE]

Todas as minhas credenciais são precisas e válidas, e o servidor está bem. Fiz o mesmo pedido com o carteiro.

request({
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":{
        "X-API-VERSION": 1,
        "X-API-KEY": key
    },
}, function(err, response, body){
    console.log(err);
    console.log(response);
    console.log(body);
});

Este código está sendo executado apenas em um script executável ex. node ./run_file.js, É por isso que? Ele precisa ser executado em um servidor?

ThomasReggi
fonte
É um tiro no escuro, mas será que a API não está reconhecendo o agente do usuário que está sendo transmitido pelo seu programa de nó?
perfil completo de Hector Correa
1
Hum ... também ver isto: blog.gaeremynck.com/fixing-unable_to_verify_leaf_signature
Hector Correa
@HectorCorrea Consegui ler perfeitamente a API no carteiro. Por que o nó não pode fazer isso? Eu tentei mudar o agente do usuário, sem sorte.
ThomasReggi

Respostas:

157

Nota : o seguinte é perigoso e permitirá que o conteúdo da API seja interceptado e modificado entre o cliente e o servidor.

Isso também funcionou

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

ThomasReggi
fonte
22
Modifiquei isso e obrigado por responder, mas isso é prejudicial à sua segurança. Você deve adicionar a CA ausente conforme a resposta do @ CoolAJ86 abaixo.
Mikemaccana 02/06
4
Eu estou usando os NodeJS plugin chamado nodemailere nodemailer-smtp-transporte o mesmo comando geral funcionou. Você precisa adicionar isso ao seu createTransportobjeto:tls:{rejectUnauthorized: false}
LukeP 15/09
3
@LukeP igualmente inseguro com o nodemailer, eu acho. Há uma pista no nome: se de algo Un autorizado, geralmente você quer rejeitá-la, por definição. O que você precisa é encontrar uma maneira de autorizá-lo corretamente (configurando os certificados da CA corretamente, como outras respostas já disseram).
Bruno
@ Bruno Eu concordo, você deve configurá-lo da maneira certa com certificados. Eu apenas queria configurar um teste rápido para uma demonstração, para que o código que publiquei seja uma solução rápida. Eu deveria ter precedido isso no meu comentário.
LukeP
1
@mikemaccana Não há problemas de segurança se a solicitação estiver no mesmo servidor e você for o único proprietário.
Binar Web
89

Não é um problema com o aplicativo, mas com o certificado assinado por uma CA intermediária. Se você aceitar esse fato e ainda quiser continuar, adicione o seguinte para solicitar opções:

rejectUnauthorized: false

Pedido completo:

request({
    "rejectUnauthorized": false,
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":{
        "X-API-VERSION": 1,
        "X-API-KEY": key
    },
}, function(err, response, body){
    console.log(err);
    console.log(response);
    console.log(body);
});
Andrei Karpushonak
fonte
Eu tenho esse problema agora no trabalho. Enviei um tíquete de TI informando que o SSL pode estar mal configurado - eles me disseram que eu era louco. Há mais informações que eu possa fornecer para resolver esse problema?
blakev
Na verdade, isso não está correto: como mencionam CoolAJ86 e hectorcorrea, o certificado é válido, mas é assinado por uma CA intermediária.
Mikemaccana
80

A solução segura

Em vez de desativar a segurança, você pode adicionar os certificados necessários à cadeia. Primeiro instale o pacote ssl-root-cas a partir do npm:

npm install ssl-root-cas

Este pacote contém muitos certificados intermediários nos quais os navegadores confiam, mas o nó não.

var sslRootCAs = require('ssl-root-cas/latest')
sslRootCAs.inject()

Irá adicionar os certificados ausentes. Veja aqui para mais informações:

https://git.coolaj86.com/coolaj86/ssl-root-cas.js

Veja também a próxima resposta abaixo

coolaj86
fonte
2
O cliente Http não usa o armazenamento de certificados das Autoridades de Certificação Raiz Confiáveis ​​do Windows?
21416 Richard Collette
1
O nó usa os certificados mozilla agrupados no binário e os substitui sempre que você fornece sua própria camatriz. Não sei se o módulo http também procurará a cadeia do sistema operacional. No entanto, a ondulação no OS X parece usar apenas a cadeia do SO e não permitir certificados manualmente especificados.
coolaj86
Isso precisa ser executado para cada processo ou posso executá-lo uma vez e atualizar meus certificados globalmente?
1937 Joshua Snider #
Os certificados são armazenados potencialmente em dois locais: (1) embutido no binário node.js (2) no keystore do sistema operacional. Se seus certificados estão desatualizados, você precisará incluí-lo no seu código de execução. Ele não altera o binário do nó nem o sistema operacional - apenas a pasta do projeto.
coolaj86
1
@ Sunkas É exatamente o que as mensagens de erro dizem. Eu não sei como explicar isso de maneira mais simples. É um arquivo somente leitura e não pode ser editado.
coolaj86 13/03
45

A solução do CoolAJ86 está correta e não compromete sua segurança, como desativar todas as verificações usando rejectUnauthorizedou NODE_TLS_REJECT_UNAUTHORIZED. Ainda assim, pode ser necessário injetar explicitamente um certificado de autoridade de certificação adicional.

Tentei primeiro as autoridades de certificação raiz incluídas no módulo ssl-root-cas :

require('ssl-root-cas/latest')
  .inject();

Eu ainda acabei com o UNABLE_TO_VERIFY_LEAF_SIGNATUREerro. Em seguida, descobri quem emitiu o certificado para o site ao qual estava me conectando pelo COMODO SSL Analyzer , baixei o certificado dessa autoridade e tentei adicionar apenas aquele:

require('ssl-root-cas/latest')
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

Acabei com outro erro: CERT_UNTRUSTED. Por fim, injetei as CAs raiz adicionais e incluí a CA "minha" (aparentemente intermediária), que funcionou:

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');
Ferdinand Prantl
fonte
1
Eu estava me conectando a um site com um certificado emitido pela CA do servidor seguro COMODO High-Assurance. Eu baixei o certificado da página de downloads .
Ferdinand Prantl
2
Obrigado! Para o meu problema, eu precisava adicionar toda a cadeia de certificados para superar esse erro. Para outros referência, este post me mostrou como é fácil exportar os arquivos PEM necessários via Firefox: superuser.com/a/97203
mfink
Bem, obrigado pela ajuda. No meu caso, no final, era uma configuração ruim do servidor SSL, não do nó. Nem todos os certificados intermediários foram instalados no servidor.
22415 Scott Jungwirth
se você receber o certificado como .cerexecutar este openssl x509 -inform DER -in YOUR_CERTIFICATE.cer -out YOUR_CERTIFICATE.crtpara convertê-lo ta .crtde antemão
0x1gene
8

Para o Create Create React App (onde esse erro também ocorre e esta pergunta é o principal resultado do Google), você provavelmente está usando HTTPS=true npm startum proxy(in package.json) que vai para alguma API HTTPS que é autoassinada quando está em desenvolvimento.

Se for esse o caso, considere mudar proxyassim:

"proxy": {
  "/api": {
    "target": "https://localhost:5001",
    "secure": false
  }
}

secure decide se o proxy WebPack verifica ou não a cadeia de certificados e desativa, o que garante que o certificado autoassinado da API não seja verificado para que você obtenha seus dados.

Tomáš Hübelbauer
fonte
4

Pode ser muito tentador fazer rejectUnauthorized: falseou process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';não fazê-lo! Expõe você ao homem nos ataques do meio.

As outras respostas estão corretas, pois o problema está no fato de o seu certificado ser "assinado por uma CA intermediária". Existe uma solução fácil para isso, que não requer uma biblioteca de terceiros, como ssl-root-casinjeta CAs adicionais no nó.

A maioria dos clientes https no nó suporta opções que permitem especificar uma CA por solicitação, que será resolvida UNABLE_TO_VERIFY_LEAF_SIGNATURE. Aqui está um exemplo simples usando o httpsmódulo interno do nó .

import https from 'https';

const options = {
  host: '<your host>',
  defaultPort: 443,
  path: '<your path>',
  // assuming the bundle file is co-located with this file
  ca: readFileSync(__dirname + '/<your bundle file>.ca-bundle'),
  headers: {
    'content-type': 'application/json',
  }
};
https.get(options, res => {
  // do whatever you need to do
})

Se, no entanto, você puder definir as configurações de SSL no servidor de hospedagem, a melhor solução seria adicionar os certificados intermediários ao seu provedor de hospedagem. Dessa forma, o solicitante do cliente não precisa especificar uma CA, pois está incluída no próprio servidor. Eu pessoalmente uso namecheap + heroku. O truque para mim foi criar um arquivo .crt com cat yourcertificate.crt bundle.ca-bundle > server.crt. Abri esse arquivo e adicionei uma nova linha após o primeiro certificado. Você pode ler mais em

https://www.namecheap.com/support/knowledgebase/article.aspx/10050/33/installing-an-ssl-certificate-on-heroku-ssl

Simon
fonte
Esse bug ocorre principalmente no ambiente local, não na produção. Portanto, se você estiver no local, é bom fazê-lo: process.env ['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
Vivex #
@Vivex - não é permitido fazer isso em um ambiente local, se o objetivo principal é testar como seus certificados SSL funcionam e como eles são transmitidos ...
dwanderson
2

Colocando isso aqui, caso isso ajude alguém, meu caso foi diferente e um pouco estranho. Eu estava recebendo isso em uma solicitação acessada via superagent - o problema não tinha nada a ver com certificados (que foram configurados corretamente) e tudo relacionado ao fato de eu estar passando o resultado do superagent pelo retorno de chamada em cascata do módulo assíncrono . Para corrigir: em vez de passar o resultado inteiro, basta passar result.bodypelo retorno de chamada da cachoeira.

k00k
fonte
2

Eu tive os mesmos problemas. Segui as soluções @ThomasReggi e @ CoolAJ86 e funcionou bem, mas não estou satisfeito com a solução.

Porque o problema "UNABLE_TO_VERIFY_LEAF_SIGNATURE" ocorreu devido ao nível de configuração da certificação.

Eu aceito a solução @thirdender, mas sua solução parcial. Conforme o site oficial da nginx , eles mencionaram claramente que o certificado deve ser a combinação de O certificado do servidor e os certificados encadeados.

insira a descrição da imagem aqui

Sharathi RB
fonte
1

Você também pode tentar configurando strictSSL para false, assim:

{  
   url: "https://...",
   method: "POST",
   headers: {
        "Content-Type": "application/json"},
   strictSSL: false
}
SUBHAJIT GANGULI
fonte
0

Eu tive um problema com minha configuração do Apache depois de instalar um certificado do GoDaddy em um subdomínio. Originalmente, pensei que poderia haver um problema com o Node não enviar um SNI (Server Name Indicator), mas esse não foi o caso. A análise do certificado SSL do subdomínio com https://www.ssllabs.com/ssltest/ retornou o erro Problemas de cadeia: incompleto .

Depois de adicionar o gd_bundle-g2-g1.crtarquivo fornecido pelo GoDaddy por meio da SSLCertificateChainFilediretiva Apache, o Node conseguiu se conectar por HTTPS e o erro desapareceu.

terceiro
fonte
0

Você precisa incluir o certificado intermediário no seu servidor. Isso resolve o [Erro: UNABLE_TO_VERIFY_LEAF_SIGNATURE]


fonte
0

Outra abordagem para solucionar isso com segurança é usar o módulo a seguir.

node_extra_ca_certs_mozilla_bundle

Este módulo pode funcionar sem nenhuma modificação de código, gerando um arquivo PEM que inclui todos os certificados raiz e intermediários confiáveis ​​pelo Mozilla. Você pode usar a seguinte variável de ambiente (Works with Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Para gerar o arquivo PEM para usar com a variável de ambiente acima. Você pode instalar o módulo usando:

npm install --save node_extra_ca_certs_mozilla_bundle

e, em seguida, inicie o script do nó com uma variável de ambiente.

NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js

Outras maneiras de usar o arquivo PEM gerado estão disponíveis em:

https://github.com/arvind-agarwal/node_extra_ca_certs_mozilla_bundle

NOTA: Eu sou o autor do módulo acima.

arva
fonte
0

Se você chegar a esse encadeamento porque está usando o módulo postgres / pg do nó, há uma solução melhor que a configuração NODE_TLS_REJECT_UNAUTHORIZEDou rejectUnauthorized, que levará a conexões inseguras.

Em vez disso, configure a opção "ssl" para corresponder aos parâmetros para tls.connect :

{
  ca: fs.readFileSync('/path/to/server-ca.pem').toString(),
  cert: fs.readFileSync('/path/to/client-cert.pem').toString(),
  key: fs.readFileSync('/path/to/client-key.pem').toString(),
  servername: 'my-server-name' // e.g. my-project-id/my-sql-instance-id for Google SQL
}

Eu escrevi um módulo para ajudar com a análise dessas opções de variáveis de ambiente como PGSSLROOTCERT, PGSSLCERT, e PGSSLKEY:

https://github.com/programmarchy/pg-ssl

Donald
fonte
0

Os seguintes comandos funcionaram para mim:

> npm config set strict-ssl false
> npm cache clean --force

O problema é que você está tentando instalar um módulo a partir de um repositório com um certificado SSL [Secure Sockets Layer] inválido ou não confiável. Depois de limpar o cache, esse problema será resolvido. Talvez seja necessário transformá-lo em verdadeiro mais tarde.

Shagun Pruthi
fonte