Nie można zweryfikować podpisu liścia

142

Aby dotrzeć do interfejsu API, używam node.js request.js. Otrzymuję ten błąd

[Błąd: UNABLE_TO_VERIFY_LEAF_SIGNATURE]

Wszystkie moje dane uwierzytelniające są dokładne i ważne, a serwer działa prawidłowo. Złożyłem tę samą prośbę z listonoszem.

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);
});

Ten kod działa po prostu w wykonywalnym skrypcie, np. node ./run_file.js, Czy to dlatego? Czy musi działać na serwerze?

ThomasReggi
źródło
To długa perspektywa, ale czy może być tak, że API nie rozpoznaje agenta użytkownika przekazywanego przez program węzłowy?
Hector Correa
1
Hum ... zobacz także: blog.gaeremynck.com/fixing-unable_to_verify_leaf_signature
Hector Correa
@HectorCorrea Udało mi się doskonale odczytać interfejs API w listonoszu. Dlaczego węzeł nie może tego zrobić? Próbowałem zmienić klienta użytkownika, bez powodzenia.
ThomasReggi

Odpowiedzi:

157

Uwaga : poniższe czynności są niebezpieczne i pozwolą na przechwytywanie i modyfikowanie zawartości API między klientem a serwerem.

To też zadziałało

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

ThomasReggi
źródło
22
Zmodyfikowałem to i dziękuję za odpowiedź, ale jest to aktywnie szkodliwe dla twojego bezpieczeństwa. Powinieneś dodać brakujący CA dla odpowiedzi @ CoolAJ86 poniżej.
mikemaccana
4
Używam NodeJS plugin o nazwie nodemaileri nodemailer-smtp-transportto samo polecenie ogóle pracował. Musisz dodać to do swojego createTransportobiektu:tls:{rejectUnauthorized: false}
LukeP
3
Wydaje mi się, że @LukeP jest równie niepewny z nodemailer. Jest wskazówką w nazwie: jeśli coś jest Un upoważniony, zazwyczaj chcą ją odrzucić, z definicji. Musisz znaleźć sposób na poprawną autoryzację (poprzez prawidłowe skonfigurowanie certyfikatów CA, jak powiedziały już inne odpowiedzi).
Bruno
@Bruno Zgadzam się, powinieneś ustawić to we właściwy sposób za pomocą certyfikatów. Chciałem tylko ustawić szybki test dla wersji demonstracyjnej, więc kod, który opublikowałem, jest szybką poprawką. Powinienem był to poprzedzić w moim komentarzu.
LukeP
1
@mikemaccana Nie ma problemu z bezpieczeństwem, jeśli żądanie jest na tym samym serwerze, a Ty jesteś jedynym właścicielem.
Binar Web
89

To nie jest problem z aplikacją, ale z certyfikatem podpisanym przez pośredniczący CA. Jeśli akceptujesz ten fakt i nadal chcesz kontynuować, dodaj następujące informacje, aby poprosić o opcje:

rejectUnauthorized: false

Pełne żądanie:

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
źródło
Mam teraz ten problem w pracy. Wysłałem zgłoszenie informatyczne z informacją, że SSL może być źle skonfigurowany - powiedzieli mi, że jestem szalony. Czy mogę udzielić im dodatkowych informacji, aby rozwiązać ten problem?
blakev
W rzeczywistości nie jest to poprawne: jak wspominają CoolAJ86 i hectorcorrea, certyfikat jest ważny, ale jest podpisany przez pośredniczący CA.
mikemaccana
80

Bezpieczne rozwiązanie

Zamiast wyłączać zabezpieczenia, możesz dodać niezbędne certyfikaty do łańcucha. Najpierw zainstaluj pakiet ssl-root-cas z npm:

npm install ssl-root-cas

Ten pakiet zawiera wiele certyfikatów pośredniczących, którym przeglądarki ufają, ale węzeł nie.

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

Doda brakujące certyfikaty. Zobacz tutaj, aby uzyskać więcej informacji:

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

Zobacz także następną odpowiedź poniżej

coolaj86
źródło
2
Czy klient HTTP nie używa magazynu certyfikatów zaufanych głównych urzędów certyfikacji systemu Windows?
Richard Collette
1
węzeł używa certyfikatów Mozilla zawartych w pliku binarnym i zastępuje je za każdym razem, gdy dostarczasz własną catablicę. Nie wiem, czy jego moduł http będzie również wyglądał na łańcuch systemu operacyjnego. Jednak funkcja curl w systemie OS X wydaje się używać tylko łańcucha systemu operacyjnego i nie zezwala na ręcznie określane certyfikaty.
coolaj86
Czy trzeba to uruchamiać dla każdego procesu, czy mogę uruchomić go raz i globalnie zaktualizować moje certyfikaty?
Joshua Snider
Certyfikaty są przechowywane w potencjalnie dwóch miejscach: (1) wbudowane w plik binarny node.js (2) magazyn kluczy systemu operacyjnego. Jeśli twoje certyfikaty są nieaktualne, musisz to uwzględnić w uruchomionym kodzie. Nie zmienia pliku binarnego węzła ani systemu operacyjnego - tylko folder projektu.
coolaj86
1
@Sunkas Dokładnie to mówią komunikaty o błędach. Nie wiem, jak to wytłumaczyć prościej. Jest to plik tylko do odczytu i nie można go edytować.
coolaj86
45

Rozwiązanie CoolAJ86 jest poprawne i nie zagraża bezpieczeństwu, jak wyłączenie wszystkich kontroli za pomocą rejectUnauthorizedlub NODE_TLS_REJECT_UNAUTHORIZED. Mimo to może być konieczne jawne wstrzyknięcie dodatkowego certyfikatu CA.

Najpierw wypróbowałem główne urzędy certyfikacji zawarte w module ssl-root-cas :

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

Nadal skończyłem z UNABLE_TO_VERIFY_LEAF_SIGNATUREbłędem. Następnie dowiedziałem się, kto wystawił certyfikat dla strony internetowej, z którą łączyłem się przez COMODO SSL Analyzer , pobrałem certyfikat tego urzędu i próbowałem dodać tylko ten:

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

Skończyło się z innym błędem: CERT_UNTRUSTED. Na koniec wstrzyknąłem dodatkowe główne CA i dołączyłem „mój” (najwyraźniej pośredni) CA, który działał:

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');
Ferdinand Prantl
źródło
1
Łączyłem się z witryną internetową posiadającą certyfikat wydany przez CA COMODO High-Assurance Secure Server. Ściągnąłem certyfikat z ich strony pobierania .
Ferdinand Prantl
2
Dziękuję Ci! W moim przypadku musiałem dodać cały łańcuch certyfikatów, aby ominąć ten błąd. Dla innych informacji ten post pokazał mi, jak łatwo wyeksportować potrzebne pliki pem przez przeglądarkę Firefox: superuser.com/a/97203
mfink
Dzięki za pomoc. W moim przypadku ostatecznie była to zła konfiguracja serwera SSL, a nie węzła. Nie wszystkie certyfikaty pośrednie zostały zainstalowane na serwerze.
Scott Jungwirth
jeśli otrzymasz certyfikat jako .ceruruchom to, openssl x509 -inform DER -in YOUR_CERTIFICATE.cer -out YOUR_CERTIFICATE.crtaby przekonwertować go .crtwcześniej
0x1gene
8

W przypadku aplikacji Create React (gdzie ten błąd również występuje, a to pytanie jest wynikiem nr 1 w Google), prawdopodobnie używasz HTTPS=true npm starti proxy(in package.json), które przechodzi do jakiegoś interfejsu API HTTPS, który sam się podpisuje, podczas opracowywania.

W takim przypadku rozważ zmianę w proxyten sposób:

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

secure decyduje, czy serwer proxy WebPack sprawdza łańcuch certyfikatów, czy też nie, i wyłączanie, które zapewnia, że ​​certyfikat z podpisem własnym interfejsu API nie jest weryfikowany, aby uzyskać dane.

Tomáš Hübelbauer
źródło
4

To może być bardzo kuszące, aby zrobić rejectUnauthorized: falsealbo process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';ale nie rób tego! Naraża cię na ataki man in the middle.

Inne odpowiedzi są poprawne, ponieważ problem polega na tym, że Twój certyfikat jest „podpisany przez pośredniczący CA”. Istnieje na to proste rozwiązanie, które nie wymaga biblioteki innej firmy, takiej jak np. ssl-root-casWstawianie dodatkowych urzędów certyfikacji do węzła.

Większość klientów https w opcjach obsługi węzłów, które pozwalają określić CA na żądanie, które zostaną rozwiązane UNABLE_TO_VERIFY_LEAF_SIGNATURE. Oto prosty przykład użycia wbudowanego httpsmodułu node .

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

Jeśli jednak możesz skonfigurować ustawienia SSL na serwerze hostingowym, najlepszym rozwiązaniem byłoby dodanie certyfikatów pośrednich do dostawcy hostingu. W ten sposób requester klienta nie musi określać urzędu certyfikacji, ponieważ jest on zawarty w samym serwerze. Osobiście używam namecheap + heroku. Sztuczka polegała na utworzeniu jednego pliku .crt z rozszerzeniem cat yourcertificate.crt bundle.ca-bundle > server.crt. Następnie otworzyłem ten plik i dodałem nową linię po pierwszym certyfikacie. Możesz przeczytać więcej na

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

Szymon
źródło
Ten błąd występuje głównie w środowisku lokalnym, a nie w środowisku produkcyjnym, więc jeśli jesteś w środowisku lokalnym, możesz to zrobić: process.env ['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
Vivex
@Vivex - nie można tego robić w środowisku lokalnym, jeśli chodzi o sprawdzenie, jak działają twoje certyfikaty SSL i jak są one przekazywane ...
dwanderson
2

Umieszczając to tutaj na wypadek, gdyby to komuś pomogło, mój przypadek był inny i trochę dziwny. Otrzymywałem to na żądanie, do którego uzyskano dostęp za pośrednictwem superagenta - problem nie miał nic wspólnego z certyfikatami (które zostały prawidłowo skonfigurowane), a wszystko z faktem, że następnie przekazywałem wynik superagenta przez wywołanie zwrotne kaskady modułu asynchronicznego . Aby naprawić: zamiast przekazywać cały wynik, po prostu przejdź result.bodyprzez wywołanie zwrotne wodospadu.

k00k
źródło
2

Miałem te same problemy. Śledziłem rozwiązanie @ThomasReggi i @ CoolAJ86 i działałem dobrze, ale nie jestem zadowolony z rozwiązania.

Ponieważ problem „UNABLE_TO_VERIFY_LEAF_SIGNATURE” występuje z powodu poziomu konfiguracji certyfikacji.

Akceptuję rozwiązanie @thirdender, ale jego częściowe rozwiązanie.Zgodnie z oficjalną witryną nginx , wyraźnie wspomniano, że certyfikat powinien być połączeniem certyfikatu serwera i powiązanych certyfikatów.

wprowadź opis obrazu tutaj

Sharathi RB
źródło
2

Możesz także spróbować, ustawiając parametr strictSSL na false, na przykład:

{  
   url: "https://...",
   method: "POST",
   headers: {
        "Content-Type": "application/json"},
   strictSSL: false
}
SUBHAJIT GANGULI
źródło
To działa, jeśli wysyłasz z aplikacji Node JS, super !!
Ally Makongo
0

Po zainstalowaniu certyfikatu GoDaddy na subdomenie wystąpił problem z konfiguracją Apache. Początkowo myślałem, że może to być problem z tym, że Node nie wysyła wskaźnika nazwy serwera (SNI), ale tak nie było. Analiza certyfikatu SSL subdomeny za pomocą https://www.ssllabs.com/ssltest/ zwróciła błąd Problemy z łańcuchem: niekompletne .

Po dodaniu gd_bundle-g2-g1.crtpliku dostarczonego przez GoDaddy za pośrednictwem SSLCertificateChainFiledyrektywy Apache, Node był w stanie połączyć się przez HTTPS i błąd zniknął.

trzecia osoba
źródło
0

Musisz dołączyć certyfikat pośredni na swoim serwerze. To rozwiązuje [Błąd: UNABLE_TO_VERIFY_LEAF_SIGNATURE]


źródło
0

Innym podejściem do bezpiecznego rozwiązania tego problemu jest użycie następującego modułu.

node_extra_ca_certs_mozilla_bundle

Moduł ten może działać bez modyfikacji kodu, generując plik PEM zawierający wszystkie certyfikaty główne i pośrednie zaufane przez Mozillę. Możesz użyć następującej zmiennej środowiskowej (działa z Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Aby wygenerować plik PEM do użycia z powyższą zmienną środowiskową. Moduł możesz zainstalować za pomocą:

npm install --save node_extra_ca_certs_mozilla_bundle

a następnie uruchom skrypt węzła ze zmienną środowiskową.

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

Inne sposoby wykorzystania wygenerowanego pliku PEM są dostępne pod adresem:

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

UWAGA: jestem autorem powyższego modułu.

arva
źródło
0

Jeśli trafisz do tego wątku, ponieważ używasz modułu node postgres / pg, istnieje lepsze rozwiązanie niż ustawienie NODE_TLS_REJECT_UNAUTHORIZEDlub rejectUnauthorized, które doprowadzi do niezabezpieczonych połączeń.

Zamiast tego skonfiguruj opcję „ssl” tak, aby odpowiadała parametrom 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
}

Pisałem moduł do pomocy z tych opcji z parsowania zmiennych środowiskowych, jak PGSSLROOTCERT, PGSSLCERToraz PGSSLKEY:

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

Donald
źródło
-1

Działały dla mnie następujące polecenia:

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

Problem polega na tym, że próbujesz zainstalować moduł z repozytorium ze złym lub niezaufanym certyfikatem SSL [Secure Sockets Layer]. Po wyczyszczeniu pamięci podręcznej problem zostanie rozwiązany i może być konieczne późniejsze przywrócenie tego stanu.

Shagun Pruthi
źródło