Lỗi: không thể xác minh chứng chỉ đầu tiên trong nodejs


141

Tôi đang cố tải xuống một tệp từ máy chủ jira bằng url nhưng tôi đang gặp lỗi. Cách đưa chứng chỉ vào mã để xác minh Lỗi:

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)

Mã Nodejs của tôi:

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

    });
});

bạn đã có thể giải quyết điều này?
sharad jain

1
tôi đã sử dụng một quy trình khác như vô hiệu hóa xác minh chứng chỉ và thực hiện
Labeo

bạn có thể giải thích thêm một chút không? Điều này sẽ thực sự hữu ích cho tôi
sharad jain

xem câu trả lời dưới đây để xác nhận chứng chỉ, chúng tôi cần phải từ chốiUnauthorized
Labeo

Câu trả lời:


120

Hãy thử thêm chứng chỉ gốc thích hợp

Đây luôn luôn là một lựa chọn an toàn hơn nhiều so với việc chấp nhận một cách mù quáng các điểm cuối trái phép, mà lần lượt chỉ nên được sử dụng như là phương sách cuối cùng.

Điều này có thể đơn giản như thêm

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

để ứng dụng của bạn.

Các gói NPM SSL Root CA (như được sử dụng ở đây) là một gói phần mềm rất hữu ích liên quan đến vấn đề này.


9
Câu trả lời này nên được sử dụng trong hầu hết các trường hợp vì nó thực sự khắc phục vấn đề thay vì vô hiệu hóa toàn bộ lợi ích của SSL.
mikemaccana

12
Như đã nêu trong mô-đun ssl-root-cas README, một trong những nguyên nhân phổ biến nhất cho vấn đề này là chứng chỉ của bạn không nhúng chứng chỉ CA trung gian. Hãy thử sửa chữa chứng chỉ của bạn trước khi thử bất cứ điều gì khác;)
Laurent VB

Bạn thậm chí có thể không yêu cầu gói SSL-root-cas. Chỉ cần đặt globalAgents.option.cert thành chứng chỉ fullchain. Đó là những gì đã giải quyết vấn đề của tôi.
smartexpert

1
mkcert không tạo chứng chỉ "fullchain". Bạn phải ghép chứng chỉ của mình với chứng chỉ gốc có sẵn $(mkcert -CAROOT)/rootCA.pemtrong tệp chứng chỉ mới và làm một cái gì đó như https.globalAgent.options.ca = fs.readFileSync('fullchain.pem')See github.com/FiloSottile/mkcert/issues/76
Frosty Z

Đối với người bảo mật, ssl-root-casmô-đun npm có yêu cầu mozilla.org mã hóa cứng git.coolaj86.com/coolaj86/ssl-root-cas.js/src/branch/master/ trộm . Nó có thể an toàn vì Mozilla nhưng có vẻ như là một vector tấn công.
Avindra Goolcharan

60

Một hack bẩn khác, sẽ làm cho tất cả các yêu cầu của bạn không an toàn:

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

8
Điều này dường như không khác với câu trả lời của Labeo ở trên , cũng nguy hiểm như vậy.
ocramot

4
Nó khác, nó không yêu cầu bất kỳ thay đổi mã hóa nào vì biến env có thể được đặt bên ngoài mã nguồn.
jzacharuk

1
Câu trả lời này là nguy hiểm. Bạn đang vô hiệu hóa bất kỳ bảo mật nào mà TLS cung cấp.
Flimm

1
Điều này làm việc cho tôi, siêu hữu ích. Trong trường hợp của tôi, tôi chỉ nói chuyện với localhost , vì vậy bảo mật không phải là vấn đề.
Mike S

Thực sự tốt chỉ để kiểm tra localhost. Chỉ cần chắc chắn rằng bạn loại bỏ nó sau khi thử nghiệm của bạn.
Nico

44

vì không thể xác minh chứng chỉ đầu tiên trong nodejs từ chối trái phép là cần thiết

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

129
Câu trả lời này là nguy hiểm. Một cái khác là an toàn hơn.
mikemaccana

3
Bằng cách đó, bạn loại bỏ bảo mật được cung cấp bởi SSL, vì vậy nó chỉ được sử dụng để phát triển.
Sylvain

11
Không kiểm tra chứng chỉ có nghĩa là bạn không thể chắc chắn về danh tính của bên kia và do đó có thể phải chịu một máy chủ giả mạo. Tuy nhiên, ngay cả khi bạn không kiểm tra chứng chỉ, bạn vẫn nhận được thông tin liên lạc được mã hóa mà không thể (dễ dàng) theo dõi. Vì vậy, việc thêm dòng này không "loại bỏ bảo mật" của SSL cũng như một nhà bình luận khác nói "vô hiệu hóa [] toàn bộ lợi ích của SSL".
Bob Pollack

4
Vô hiệu hóa xác minh SSL KHÔNG phải là giải pháp cho bất kỳ vấn đề nào. :-)
Siddhu

9
Điều này hoạt động nếu bạn đang sử dụng thư viện yêu cầu nút. Mà tôi đang. Và cảm ơn bạn, nó giải quyết nhu cầu phát triển ngay lập tức của tôi.
Alan

29

Máy chủ bạn đang cố tải xuống có thể bị cấu hình kém. Ngay cả khi nó hoạt động trong trình duyệt của bạn, nó có thể không bao gồm tất cả các chứng chỉ công khai trong chuỗi cần thiết cho một máy khách trống bộ đệm để xác minh.

Tôi khuyên bạn nên kiểm tra trang web trong công cụ SSLlabs: https://www.ssllabs.com/ssltest/

Tìm lỗi này:

Chuỗi chứng chỉ của máy chủ này không đầy đủ.

Và điều này:

Các vấn đề về chuỗi ......... Chưa hoàn thành


Tôi gặp sự cố này (Sự cố chuỗi ......... Chưa hoàn tất) đối với chứng chỉ của tôi được ủy quyền từ DigiCert Inc., quy trình để khắc phục vấn đề này là gì?
imarchuang

@imarchuang Tóm lại, máy chủ của bạn cần phục vụ không chỉ chứng chỉ cho tên miền của bạn, mà cả chứng chỉ trung gian nữa. Tôi không thể phù hợp với chi tiết hơn trong bình luận này nhưng hy vọng đó là đủ thông tin để chỉ cho bạn đi đúng hướng.
Flimm

cảm ơn rất nhiều, chúng tôi đã tìm ra bằng cách kết hợp chứng chỉ gốc
imarchuang

Cảm ơn bạn! Tôi phát hiện ra chứng chỉ của mình chưa hoàn chỉnh, mặc dù nó hoạt động hoàn hảo trong chrome và firefox nhưng không hoạt động trong ứng dụng điện tử và tôi đã sửa nó ở bên nginx bởicat domainname.crt domainname.ca-bundle > domainname-ssl-bundle.crt
Ivan Borshchov

25

unable to verify the first certificate

Chuỗi chứng chỉ không đầy đủ.

Điều đó có nghĩa là máy chủ web bạn đang kết nối bị định cấu hình sai và không bao gồm chứng chỉ trung gian trong chuỗi chứng chỉ mà nó gửi cho bạn.

Chuỗi chứng chỉ

Nó rất có thể trông như sau:

  1. Chứng chỉ máy chủ - lưu trữ chứng chỉ được ký bởi trung gian.
  2. Chứng chỉ trung gian - lưu trữ một chứng chỉ được ký bởi root.
  3. Chứng chỉ gốc - lưu trữ chứng chỉ tự ký.

Chứng chỉ trung gian nên được cài đặt trên máy chủ, cùng với chứng chỉ máy chủ.
Chứng chỉ gốc được nhúng vào các ứng dụng phần mềm, trình duyệt và hệ điều hành.

Ứng dụng phục vụ chứng chỉ phải gửi chuỗi hoàn chỉnh, điều này có nghĩa là chính chứng chỉ máy chủ và tất cả các trung gian. Chứng chỉ gốc được cho là do khách hàng biết.

Tái tạo vấn đề

Truy cập https://incomplete-chain.badssl.com bằng trình duyệt của bạn.

Nó không hiển thị bất kỳ lỗi nào (ổ khóa trong thanh địa chỉ là màu xanh lá cây).
Đó là bởi vì các trình duyệt có xu hướng hoàn thành chuỗi nếu nó không được gửi từ máy chủ.

Bây giờ, kết nối với https://incomplete-chain.badssl.com bằng Node:

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

Nhật ký: " Lỗi: không thể xác minh chứng chỉ đầu tiên ".

Giải pháp

Bạn cần phải tự hoàn thành chuỗi chứng chỉ.

Để làm việc đó:

1: Bạn cần lấy chứng chỉ trung gian bị thiếu ở .pemđịnh dạng, sau đó

2a: mở rộng kho chứng chỉ tích hợp của Node bằng cách sử dụng NODE_EXTRA_CA_CERTS,

2b: hoặc vượt qua gói chứng chỉ của riêng bạn (trung gian và root) bằng cách sử dụng catùy chọn.

1. Làm thế nào để tôi có được chứng chỉ trung gian?

Sử dụng openssl(đi kèm với Git cho Windows ).

Lưu chi tiết chứng chỉ của máy chủ từ xa:

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

Chúng tôi đang tìm kiếm nhà phát hành (chứng chỉ trung gian là nhà phát hành / người ký chứng chỉ máy chủ):

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

Nó sẽ cung cấp cho bạn URI của chứng chỉ ký. Tải xuống:

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

Cuối cùng, chuyển đổi nó thành .pem:

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

2a. NODE_EXTRA_CERTS

Tôi đang sử dụng cross-env để đặt các biến môi trường trong package.jsontệp:

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

2b. caLựa chọn

Tùy chọn này sẽ ghi đè lên các CA gốc tích hợp của Node.

Đó là lý do tại sao chúng ta cần tạo CA gốc của mình. Sử dụng ssl-root-cas .

Sau đó, tạo một httpstác nhân tùy chỉnh được cấu hình với gói chứng chỉ của chúng tôi (gốc và trung gian). Thông qua đại lý này axioskhi thực hiện yêu cầu.

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

Thay vì tạo một httpstác nhân tùy chỉnh và chuyển nó đến axios, bạn có thể đặt các chứng nhận trên httpstác nhân toàn cầu:

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

Tài nguyên:

  1. https://levelup.gitconnected.com/how-to-resolve-certert-errors-in-nodejs-app-involve-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/ledgeledridease/article.aspx/9605/69/how-to-check-ca-chain-installation
  5. /superuser/97201/how-to-save-a-remote-server-ssl-certert-locally-as-a-file/
  6. Cách chuyển đổi .crt sang .pem

Giải thích rất chi tiết.
Bảy

Hoàn toàn tuyệt vời! Không làm việc cho tôi, nhưng thật là một chi tiết!
Tom Chadaravicius

6

Điều này thực sự đã giải quyết nó cho tôi, từ 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
Đó là giải pháp tốt nhất, vì nó không yêu cầu thêm thư viện và rất đơn giản
Martin Schneider

4

Bạn có thể làm điều này bằng cách sửa đổi các tùy chọn yêu cầu như dưới đây. Nếu bạn đang sử dụng chứng chỉ tự ký hoặc một trung gian bị thiếu, việc đặt nghiêm ngặtSSL thành false sẽ không buộc gói yêu cầu xác thực chứng chỉ.

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

Điều này đã giải quyết vấn đề của tôi, tôi đang sử dụng mô-đun 'request' thay vì 'http'. Cảm ơn!
Bruno Nunes

2

Giấy chứng nhận SSL GoDaddy

Tôi đã trải nghiệm điều này trong khi cố gắng kết nối với máy chủ API phụ trợ của chúng tôi bằng chứng chỉ GoDaddy và đây là mã mà tôi đã sử dụng để giải quyết vấn đề.

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;

Tái bút

Sử dụng chứng chỉ đi kèm và đừng quên cài đặt thư viện npm install ssl-root-cas


1
điều này làm việc cho tôi ngoại trừ khi nhập, tôi phải sử dụng "ssl-root-cas" thay vì "ssl-root-cas / mới nhất".
krishnan

2

Điều này làm việc cho tôi => thêm tác nhân và 'từ chốiUnauthorized' được đặt thành 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

Một cách tiếp cận khác để giải quyết điều này là sử dụng mô-đun sau.

node_extra_ca_certs_mozilla_bundle

Mô-đun này có thể hoạt động mà không cần sửa đổi mã bằng cách tạo tệp PEM bao gồm tất cả các chứng chỉ gốc và trung gian được Mozilla tin cậy. Bạn có thể sử dụng biến môi trường sau (Hoạt động với Nodejs v7.3 +),

NODE_EXTRA_CA_CERTS

Để tạo tệp PEM để sử dụng với biến môi trường trên. Bạn có thể cài đặt mô-đun bằng cách sử dụng:

npm install --save node_extra_ca_certs_mozilla_bundle

và sau đó khởi chạy tập lệnh nút của bạn với một biến môi trường.

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

Các cách khác để sử dụng tệp PEM được tạo có sẵn tại:

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

LƯU Ý: Tôi là tác giả của mô-đun trên.


-3

Tôi đã sử dụng mô-đun npmemailer npm. Các mã dưới đây đã giải quyết vấn đề

     tls: {
     // do not fail on invalid certs
     rejectUnauthorized: false
     }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.