오류 : nodejs에서 첫 번째 인증서를 확인할 수 없습니다


141

URL을 사용하여 jira 서버에서 파일을 다운로드하려고하는데 오류가 발생합니다. 오류 를 확인하기 위해 코드에 인증서를 포함시키는 방법 :

Error: unable to verify the first certificate in nodejs

at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:929:36)

  at TLSSocket.emit (events.js:104:17)

at TLSSocket._finishInit (_tls_wrap.js:460:8)

내 Nodejs 코드 :

var https = require("https");
var fs = require('fs');
var options = {
    host: 'jira.example.com',
    path: '/secure/attachment/206906/update.xlsx'
};

https.get(options, function (http_res) {

    var data = "";


    http_res.on("data", function (chunk) {

        data += chunk;
    });


    http_res.on("end", function () {

        var file = fs.createWriteStream("file.xlsx");
        data.pipe(file);

    });
});

이 문제를 해결할 수 있었습니까?
sharad jain

1
인증서 확인 비활성화와 같은 다른 절차를 사용했습니다
Labeo

좀 더 정교하게 할 수 있습니까? 이것은 나를 위해 정말 도움이 될 것입니다
샤 라드의 자이나교

인증서의 유효성에 대한 답은 아래를 참조하십시오 우리는 rejectUnauthorized이 필요합니다
Labeo

답변:


120

적절한 루트 인증서를 추가하십시오

이것은 무단 엔드 포인트를 맹목적으로 받아들이는 것보다 항상 훨씬 안전한 옵션이 될 것이며, 이는 마지막 수단으로 만 사용해야합니다.

이것은 추가하는 것만 큼 간단 할 수 있습니다

require('https').globalAgent.options.ca = require('ssl-root-cas/latest').create();

응용 프로그램에.

SSL 루트 CA는 NPM 패키지 (로 여기에 사용)이 문제에 대한 매우 유용한 패키지입니다.


9
이 답변은 SSL의 전체 이점을 비활성화하지 않고 실제로 문제를 해결하므로 대부분의 경우에 사용해야합니다.
mikemaccana

12
ssl-root-cas 모듈 README에 명시된 바와 같이이 문제의 가장 일반적인 원인 중 하나는 인증서가 중간 CA 인증서를 포함하지 않기 때문입니다. 다른 것을 시도하기 전에 인증서를 수정 해보십시오;)
Laurent VB

SSL-root-cas 패키지가 필요하지 않을 수도 있습니다. globalAgents.option.cert를 전체 체인 인증서로 설정하십시오. 그것이 내 문제를 해결 한 것입니다.
smartexpert

1
mkcert 는 "풀 체인"인증서를 생성하지 않습니다. $(mkcert -CAROOT)/rootCA.pem새 인증서 파일에서 사용 가능한 루트 인증서와 인증서를 연결 하고 github.com/FiloSottile/mkcert/issues/76https.globalAgent.options.ca = fs.readFileSync('fullchain.pem')
Frosty Z

보안이있는 마음의 경우, ssl-root-casNPM 모듈은 mozilla.org 하드에 대한 요청이 git.coolaj86.com/coolaj86/ssl-root-cas.js/src/branch/master/...을 . 모질라 때문에 아마 안전하지만 공격 벡터처럼 보입니다.
Avindra Goolcharan

60

또 다른 더러운 해킹으로 모든 요청이 안전하지 않게됩니다.

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

8
이것은 위와 같은 Labeo의 답변 과 다르지 않은 것처럼 보입니다 .
ocramot

4
env 변수를 소스 코드 외부에서 설정할 수 있으므로 코딩 변경이 필요하지 않습니다.
자차 룩

1
이 답변은 위험합니다. TLS가 제공하는 보안을 비활성화했습니다.
Flimm

1
이것은 나를 위해 도움이되었습니다. 내 경우에는 그냥 localhost 와 대화하고 있으므로 보안에 문제가 없습니다.
Mike S

실제로 localhost를 테스트하는 것이 좋습니다. 테스트 후에 반드시 제거하십시오.
니코

44

nodejs의 첫 번째 인증서를 확인할 수 없으므로 무단 거부가 필요합니다.

 request({method: "GET", 
        "rejectUnauthorized": false, 
        "url": url,
        "headers" : {"Content-Type": "application/json",
        function(err,data,body) {
    }).pipe(
       fs.createWriteStream('file.html'));

129
이 답변은 위험합니다. 다른 하나는 더 안전합니다.
mikemaccana

3
이를 수행하면 SSL에서 제공하는 보안을 제거하므로 개발에만 사용해야합니다.
Sylvain

11
인증서를 확인하지 않으면 상대방의 신원을 확인할 수 없으므로 스푸핑 된 호스트가 적용될 수 있습니다. 그러나 인증서를 확인하지 않더라도 (쉽게) 감시 할 수없는 암호화 된 통신이 계속 나타납니다. 따라서이 줄을 추가해도 SSL의 "보안이 제거되지"않으며 다른 주석 작성자가 "SSL의 전체 이점을 비활성화 []"한다고 말하지 않았습니다.
밥 폴락

4
SSL 확인 비활성화는 어떤 문제에 대한 해결책이 아닙니다. :-)
Siddhu

9
노드 요청 라이브러리를 사용하는 경우 작동합니다. 나는 감사합니다. 개발에 대한 즉각적인 요구가 해결되었습니다.
Alan

29

다운로드하려는 서버가 잘못 구성되었을 수 있습니다. 브라우저에서 작동하더라도 캐시가 비어있는 클라이언트를 확인하는 데 필요한 모든 공용 인증서를 체인에 포함하지 않을 수 있습니다.

SSLlabs 도구에서 사이트를 확인하는 것이 좋습니다. https://www.ssllabs.com/ssltest/

이 오류를 찾으십시오.

이 서버의 인증서 체인이 불완전합니다.

이:

체인 문제 ............ 불완전


DigiCert Inc.에서 인증 한 내 인증서에 대해이 문제 (체인 문제 ......... 불완전)를 받았습니다.이 문제를 해결하는 절차는 무엇입니까?
imarchuang

@imarchuang 간단히 말해 서버는 도메인의 인증서뿐만 아니라 중간 인증서도 제공해야합니다. 이 의견에 더 자세히 설명 할 수는 없지만 올바른 방향으로 안내하기에 충분한 정보가되기를 바랍니다.
Flimm

고마워요, 우리는 루트 인증서를 빗겨 서 알아 냈습니다
imarchuang

감사합니다! 나는 크롬과 파이어 폭스에서 완벽하게 작동하지만, 전자 응용 프로그램에서 작업을하지 않았지만 내 인증서가 불완전 발견, 나는에 의해 nginx를 측면에 고정cat domainname.crt domainname.ca-bundle > domainname-ssl-bundle.crt
이반 Borshchov

26

unable to verify the first certificate

인증서 체인이 불완전합니다.

연결하려는 웹 서버가 잘못 구성되어 전송 한 인증서 체인에 중간 인증서가 포함되지 않았 음을 의미합니다.

인증서 체인

다음과 같이 보입니다.

  1. 서버 인증서-중간에서 서명 한 인증서를 저장합니다.
  2. 중간 인증서-루트가 서명 한 인증서를 저장합니다.
  3. 루트 인증서-자체 서명 된 인증서를 저장합니다.

중간 인증서는 서버 인증서와 함께 서버에 설치해야합니다.
루트 인증서는 소프트웨어 응용 프로그램, 브라우저 및 운영 체제에 포함되어 있습니다.

인증서를 제공하는 응용 프로그램은 완전한 체인을 보내야합니다. 이는 서버 인증서 자체와 모든 중간체를 의미합니다. 루트 인증서는 클라이언트가 알고 있어야합니다.

문제를 재현

https://incomplete-chain.badssl.com으로 이동브라우저를 사용하여 하십시오.

오류가 표시되지 않습니다 (주소 표시 줄의 자물쇠가 녹색 임). 브라우저가 체인을 완성하는 경향이
있기 때문입니다 가 서버에서 전송되지 않으면 입니다.

이제 Node를 사용하여 https://incomplete-chain.badssl.com에 연결 하십시오 .

// index.js
const axios = require('axios');

axios.get('https://incomplete-chain.badssl.com')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

로그 : " 오류 : 첫 번째 인증서를 확인할 수 없습니다 ".

해결책

인증서 체인을 직접 작성해야합니다.

하기 위해서:

1 : 누락 된 중간 인증서를 .pem형식으로 가져와야합니다.

A : 확장 노드에 내장 된 인증서 저장소를 사용 NODE_EXTRA_CA_CERTS,

2b : 또는 ca옵션을 사용하여 고유 한 인증서 번들 (중간체 및 루트)을 전달하십시오 .

1. 중간 증명서는 어떻게 받습니까?

사용 openssl( Git for Windows 와 함께 제공 )

원격 서버의 인증서 세부 사항을 저장하십시오.

openssl s_client -connect incomplete-chain.badssl.com:443 -servername incomplete-chain.badssl.com | tee logcertfile

우리는 발급자를 찾고 있습니다 (중간 인증서는 서버 인증서의 발급자 / 서명자입니다).

openssl x509 -in logcertfile -noout -text | grep -i "issuer"

서명 인증서의 URI를 제공해야합니다. 다운로드 해:

curl --output intermediate.crt http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt

마지막으로 다음과 같이 변환하십시오 .pem.

openssl x509 -inform DER -in intermediate.crt -out intermediate.pem -text

2a. NODE_EXTRA_CERTS

크로스 환경 을 사용하여 package.json파일 에서 환경 변수를 설정하고 있습니다.

"start": "cross-env NODE_EXTRA_CA_CERTS=\"C:\\Users\\USERNAME\\Desktop\\ssl-connect\\intermediate.pem\" node index.js"

2b. ca선택권

이 옵션은 노드의 내장 루트 CA를 덮어 씁니다.

그렇기 때문에 자체 루트 CA를 만들어야합니다. ssl-root-cas를 사용하십시오 .

그런 다음 https인증서 번들 (루트 및 중간)로 구성된 사용자 정의 에이전트를 작성하십시오 . axios요청 시이 에이전트를 전달하십시오 .

// index.js
const axios = require('axios');
const path = require('path');
const https = require('https');
const rootCas = require('ssl-root-cas').create();

rootCas.addFile(path.resolve(__dirname, 'intermediate.pem'));
const httpsAgent = new https.Agent({ca: rootCas});

axios.get('https://incomplete-chain.badssl.com', { httpsAgent })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

사용자 정의 https에이전트 를 작성하여로 전달하는 axios대신 https글로벌 에이전트 에 인증서를 배치 할 수 있습니다 .

// Applies to ALL requests (whether using https directly or the request module)
https.globalAgent.options.ca = rootCas;

자원:

  1. https://levelup.gitconnected.com/how-to-resolve-certificate-errors-in-nodejs-app-involving-ssl-calls-781ce48daded
  2. https://www.npmjs.com/package/ssl-root-cas
  3. https://github.com/nodejs/node/issues/16336
  4. https://www.namecheap.com/support/knowledgebase/article.aspx/9605/69/how-to-check-ca-chain-installation
  5. /superuser/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file/
  6. .crt를 .pem로 변환하는 방법

매우 자세한 설명.
5

정말 대단해! 나를 위해 일하지 않았다, 그러나 세부 사항!
Tom Chadaravicius

6

이것은 실제로 나를 위해 https://www.npmjs.com/package/ssl-root-cas 에서 해결했습니다.

// INCORRECT (but might still work)
var server = https.createServer({
  key: fs.readFileSync('privkey.pem', 'ascii'),
  cert: fs.readFileSync('cert.pem', 'ascii') // a PEM containing ONLY the SERVER certificate
});

// CORRECT (should always work)
var server = https.createServer({
  key: fs.readFileSync('privkey.pem', 'ascii'),
  cert: fs.readFileSync('fullchain.pem', 'ascii') // a PEM containing the SERVER and ALL INTERMEDIATES
});

1
추가 라이브러리가 필요하지 않고 간단하기 때문에 이것이 최고의 솔루션입니다.
Martin Schneider

4

아래와 같이 요청 옵션을 수정하여이 작업을 수행 할 수 있습니다. 자체 서명 된 인증서 또는 누락 된 중개자를 사용하는 경우 strictSSL을 false로 설정하면 요청 패키지가 인증서의 유효성을 검증하지 않습니다.

var options = {
   host: 'jira.example.com',
   path: '/secure/attachment/206906/update.xlsx',
   strictSSL: false
}

이것은 내 문제를 해결했습니다 .'http '대신'request '모듈을 사용하고 있습니다. 감사!
Bruno Nunes 2019

2

GoDaddy SSL 인증서

GoDaddy 인증서로 백엔드 API 서버에 연결하려고 할 때이 문제가 발생했으며 문제를 해결하는 데 사용한 코드는 다음과 같습니다.

var rootCas = require('ssl-root-cas/latest').create();

rootCas
  .addFile(path.join(__dirname, '../config/ssl/gd_bundle-g2-g1.crt'))
  ;

// will work with all https requests will all libraries (i.e. request.js)
require('https').globalAgent.options.ca = rootCas;

추신:

번들 인증서를 사용하고 라이브러리를 설치하는 것을 잊지 마십시오 npm install ssl-root-cas


1
가져 오는 동안 "ssl-root-cas / latest"대신 "ssl-root-cas"를 사용해야한다는 점을 제외하고는 저에게 효과적이었습니다.
krishnan 2016 년

2

이것은 나를 위해 일했다 => 에이전트 추가 및 'rejectUnauthorized'가 false로 설정 됨

const https = require('https'); //Add This
const bindingGridData = async () => {
  const url = `your URL-Here`;
  const request = new Request(url, {
    method: 'GET',
    headers: new Headers({
      Authorization: `Your Token If Any`,
      'Content-Type': 'application/json',
    }),
    //Add The Below
    agent: new https.Agent({
      rejectUnauthorized: false,
    }),
  });
  return await fetch(request)
    .then((response: any) => {
      return response.json();
    })
    .then((response: any) => {
      console.log('response is', response);
      return response;
    })
    .catch((err: any) => {
      console.log('This is Error', err);
      return;
    });
};


1

이 문제를 해결하는 또 다른 방법은 다음 모듈을 사용하는 것입니다.

node_extra_ca_certs_mozilla_bundle

이 모듈은 Mozilla가 신뢰하는 모든 루트 및 중간 인증서를 포함하는 PEM 파일을 생성하여 코드를 수정하지 않고도 작동 할 수 있습니다. 다음 환경 변수를 사용할 수 있습니다 (Nodejs v7.3 +에서 작동).

NODE_EXTRA_CA_CERTS

위 환경 변수와 함께 사용할 PEM 파일을 생성합니다. 다음을 사용하여 모듈을 설치할 수 있습니다.

npm install --save node_extra_ca_certs_mozilla_bundle

그런 다음 환경 변수를 사용하여 노드 스크립트를 시작하십시오.

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

생성 된 PEM 파일을 사용하는 다른 방법은 다음에서 사용 가능합니다.

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

참고 : 위 모듈의 저자입니다.


-3

nodemailer npm 모듈을 사용하고있었습니다. 아래 코드는 문제를 해결했습니다.

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.