ไม่สามารถยืนยันลายเซ็นใบไม้


142

ฉันกำลังใช้ node.js request.js เพื่อเข้าถึง API ฉันได้รับข้อผิดพลาดนี้

[ข้อผิดพลาด: UNABLE_TO_VERIFY_LEAF_SIGNATURE]

ข้อมูลรับรองทั้งหมดของฉันถูกต้องและถูกต้องและเป็นผลดีกับเซิร์ฟเวอร์ ฉันทำคำขอเดียวกันกับบุรุษไปรษณีย์

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

รหัสนี้เพิ่งทำงานในสคริปต์ที่ปฏิบัติการได้ node ./run_file.jsนั่นคือเหตุผลที่? มันจำเป็นต้องทำงานบนเซิร์ฟเวอร์หรือไม่?


นี่เป็นช็อตที่ยาว แต่เป็นไปได้ไหมว่า API ไม่รู้จักเอเจนต์ผู้ใช้ที่ถูกส่งผ่านโดยโปรแกรมโหนดของคุณ?
Hector Correa

1
ฮัม ... ยังเห็นเช่นนี้: blog.gaeremynck.com/fixing-unable_to_verify_leaf_signature
Hector Correa

@HectorCorrea ฉันสามารถอ่าน API ในบุรุษไปรษณีย์ได้อย่างสมบูรณ์แบบ ทำไมโหนดไม่สามารถทำได้ ฉันพยายามเปลี่ยนตัวแทนผู้ใช้ไม่มีโชค
ThomasReggi

คำตอบ:


157

หมายเหตุ : สิ่งต่อไปนี้เป็นอันตรายและจะอนุญาตให้เนื้อหา API ถูกดักจับและแก้ไขระหว่างไคลเอนต์และเซิร์ฟเวอร์

สิ่งนี้ยังใช้งานได้

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


22
ฉันอัปเดตสิ่งนี้และขอขอบคุณที่ตอบ แต่มันเป็นอันตรายต่อความปลอดภัยของคุณ คุณควรเพิ่ม CA ที่หายไปตามคำตอบของ @ CoolAJ86 ด้านล่าง
mikemaccana

4
ฉันใช้ปลั๊กอิน NodeJS ชื่อnodemailerและnodemailer-smtp-transportและคำสั่งทั่วไปเดียวกันทำงาน คุณต้องเพิ่มสิ่งนี้ลงในcreateTransportวัตถุของคุณ:tls:{rejectUnauthorized: false}
ลุค

3
@LukeP ไม่ปลอดภัยเท่า ๆ กันกับผู้ที่ไม่ต้องการอีเมลฉันเดาว่า มีเงื่อนงำในชื่อ: หากมีบางสิ่งบางอย่างที่ไม่ได้รับอนุญาตคุณมักจะต้องการปฏิเสธโดยคำจำกัดความ สิ่งที่คุณต้องการคือการหาวิธีอนุญาตอย่างถูกต้อง (โดยการตั้งค่าใบรับรอง CA อย่างถูกต้องตามคำตอบอื่น ๆ ที่ได้กล่าวไปแล้ว)
บรูโน่

@Bruno ฉันเห็นด้วยคุณควรตั้งค่าอย่างถูกต้องด้วยใบรับรอง ฉันแค่ต้องการตั้งค่าการทดสอบอย่างรวดเร็วสำหรับตัวอย่างเพื่อให้รหัสที่ฉันโพสต์เป็นการแก้ไขด่วน ฉันควรจะนำไปใช้กับสิ่งนั้นในความคิดเห็นของฉัน
LukeP

1
@mikemaccana ไม่มีปัญหาด้านความปลอดภัยหากคำขออยู่บนเซิร์ฟเวอร์เดียวกันและคุณเป็นเจ้าของคนเดียว
Binar Web

89

ไม่ใช่ปัญหาเกี่ยวกับแอปพลิเคชัน แต่มีใบรับรองซึ่งลงนามโดย CA ตัวกลาง หากคุณยอมรับความจริงนั้นและยังต้องการดำเนินการต่อให้เพิ่มตัวเลือกต่อไปนี้เพื่อร้องขอ:

rejectUnauthorized: false

คำขอเต็มรูปแบบ:

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

ฉันมีปัญหานี้ในที่ทำงาน ฉันส่งตั๋วด้านไอทีเพื่อบอกว่า SSL อาจมีการกำหนดค่าผิดพลาด - พวกเขาบอกว่าฉันบ้ามาก มีข้อมูลเพิ่มเติมที่ฉันสามารถให้พวกเขาเพื่อแก้ไขปัญหานี้หรือไม่?
blakev

สิ่งนี้ไม่ถูกต้องจริง ๆ : เนื่องจาก CoolAJ86 และ hectorcorrea พูดถึงใบรับรองนั้นถูกต้อง แต่มันถูกลงนามโดย CA ตัวกลาง
mikemaccana

80

โซลูชันที่ปลอดภัย

แทนที่จะปิดการรักษาความปลอดภัยคุณสามารถเพิ่มใบรับรองที่จำเป็นในห่วงโซ่ ติดตั้งแพ็กเกจssl-root-casครั้งแรกจาก npm:

npm install ssl-root-cas

แพคเกจนี้ประกอบด้วยใบรับรองตัวกลางจำนวนมากที่เบราว์เซอร์เชื่อถือ แต่โหนดไม่มี

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

จะเพิ่มใบรับรองที่หายไป ดูที่นี่สำหรับข้อมูลเพิ่มเติม:

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

ดูคำตอบถัดไปด้านล่าง


2
ไคลเอนต์ Http ไม่ได้ใช้ที่เก็บใบรับรองผู้ออกใบรับรอง Windows Trusted Root หรือไม่
Richard Collette

1
โหนดใช้ mozilla certs ที่รวมอยู่ในไบนารีและมันจะแทนที่พวกเขาทุกครั้งที่คุณจัดหาcaอาร์เรย์ของคุณเอง ฉันไม่รู้ว่าโมดูล http ของมันจะมองไปที่เชน OS หรือไม่ อย่างไรก็ตามดูเหมือนว่า curl บน OS X จะใช้งานโซ่ระบบปฏิบัติการเท่านั้นและไม่อนุญาตให้ใช้ใบรับรองที่ระบุด้วยตนเอง
coolaj86

ต้องดำเนินการนี้สำหรับแต่ละกระบวนการหรือฉันสามารถเรียกใช้ได้หนึ่งครั้งและอัปเดตใบรับรองของฉันทั่วโลกหรือไม่
Joshua Snider

ใบรับรองถูกเก็บในที่สองที่อาจเกิดขึ้น: (1) บิวด์อินของ node.js ไบนารี (2) ที่เก็บคีย์ระบบปฏิบัติการ หากใบรับรองของคุณล้าสมัยคุณจะต้องรวมสิ่งนี้ไว้ในรหัสเรียกใช้ของคุณ มันจะไม่เปลี่ยนโหนดไบนารีหรือระบบปฏิบัติการของคุณ - เพียงแค่โฟลเดอร์โครงการ
coolaj86

1
@Sunkas มันเป็นสิ่งที่ข้อความผิดพลาดบอก ฉันไม่รู้จะอธิบายให้ง่ายขึ้นได้อย่างไร เป็นไฟล์แบบอ่านอย่างเดียวและไม่สามารถแก้ไขได้
coolaj86

45

วิธีการแก้ปัญหาของ CoolAJ86 ถูกต้องและจะไม่ยอมความปลอดภัยของคุณเช่นการปิดใช้งานการตรวจสอบทั้งหมดที่ใช้หรือrejectUnauthorized NODE_TLS_REJECT_UNAUTHORIZEDถึงกระนั้นคุณอาจต้องฉีดใบรับรองของ CA เพิ่มเติมอย่างชัดเจน

ฉันลอง CA รูตแรกที่รวมอยู่ในโมดูลssl-root-cas :

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

ฉันยังคงลงเอยด้วยUNABLE_TO_VERIFY_LEAF_SIGNATUREข้อผิดพลาด จากนั้นฉันก็พบว่าใครเป็นผู้ออกใบรับรองสำหรับเว็บไซต์ที่ฉันกำลังเชื่อมต่อโดยCOMODO SSL Analyzerดาวน์โหลดใบรับรองของผู้มีสิทธิ์นั้นและพยายามที่จะเพิ่มเฉพาะที่:

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

ฉันลงเอยด้วยข้อผิดพลาดอื่น: CERT_UNTRUSTED. ในที่สุดฉันฉีด CA รูตเพิ่มเติมและรวม CA "ของฉัน" (ดูเหมือนว่าเป็นคนกลาง) ซึ่งทำงาน:

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

1
ฉันกำลังเชื่อมต่อไปยังเว็บไซต์ที่มีใบรับรองที่ออกโดยเซิร์ฟเวอร์ความปลอดภัยสูง COMODO CA ฉันดาวน์โหลดใบรับรองจากพวกเขาหน้าดาวน์โหลด
Ferdinand Prantl

2
ขอบคุณ! สำหรับปัญหาของฉันฉันต้องเพิ่มเชนทั้งหมดเพื่อให้ผ่านข้อผิดพลาดนี้ สำหรับการอ้างอิงอื่นโพสต์นี้แสดงให้ฉันเห็นวิธีการส่งออกไฟล์ pem ที่จำเป็นผ่าน Firefox: superuser.com/a/97203
mfink

ขอบคุณมากสำหรับความช่วยเหลือ ในกรณีของฉันในที่สุดมันเป็นการกำหนดค่าที่ไม่ดีของเซิร์ฟเวอร์ SSL ไม่ใช่โหนด ไม่ได้ติดตั้ง certs ระดับกลางทั้งหมดไว้บนเซิร์ฟเวอร์
Scott Jungwirth

หากคุณได้รับใบรับรองเป็นการ.cerเรียกใช้openssl x509 -inform DER -in YOUR_CERTIFICATE.cer -out YOUR_CERTIFICATE.crtเพื่อแปลงเป็น ta .crtล่วงหน้า
0x1gene

8

สำหรับแอปสร้างการตอบโต้ (ที่ข้อผิดพลาดนี้เกิดขึ้นด้วยและคำถามนี้คือผลลัพธ์อันดับ # 1 ของ Google) คุณอาจใช้HTTPS=true npm startและproxy(ในpackage.json) ซึ่งไปยัง HTTPS API บางตัวที่ลงชื่อด้วยตนเองเมื่ออยู่ในการพัฒนา

หากเป็นกรณีนี้ให้ลองพิจารณาเปลี่ยนแปลงproxyดังนี้:

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

secure ตัดสินใจว่าพร็อกซี WebPack ตรวจสอบห่วงโซ่ใบรับรองหรือไม่และปิดใช้งานเพื่อให้แน่ใจว่าใบรับรองที่ลงชื่อด้วยตนเองของ API ไม่ได้รับการตรวจสอบเพื่อให้คุณได้รับข้อมูลของคุณ


4

มันอาจเป็นเรื่องล่อลวงให้ทำrejectUnauthorized: falseหรือprocess.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';ไม่ทำมัน! มันทำให้คุณพบกับมนุษย์ในการโจมตีระดับกลาง

คำตอบอื่น ๆ นั้นถูกต้องในประเด็นที่ว่าใบรับรองของคุณนั้น "ลงนามโดย CA ตัวกลาง" มีวิธีแก้ปัญหาที่ง่ายซึ่งไม่ต้องใช้ssl-root-casไลบรารี่ของบุคคลที่สามเช่นหรือเพิ่ม CAs ใด ๆ ลงในโหนด

ไคลเอ็นต์ https ส่วนใหญ่ในตัวเลือกการสนับสนุนโหนดที่อนุญาตให้คุณระบุ CA ต่อคำขอซึ่งจะแก้ไขUNABLE_TO_VERIFY_LEAF_SIGNATUREได้ นี่คือตัวอย่างง่ายๆโดยใช้httpsโมดูลในตัวของโหนด

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

อย่างไรก็ตามหากคุณสามารถกำหนดการตั้งค่า ssl ในเซิร์ฟเวอร์การโฮสต์ของคุณได้ทางออกที่ดีที่สุดคือการเพิ่มใบรับรองระดับกลางให้กับผู้ให้บริการโฮสต์ของคุณ ด้วยวิธีนี้ผู้ร้องขอของลูกค้าไม่จำเป็นต้องระบุ CA เนื่องจากจะรวมอยู่ในเซิร์ฟเวอร์เอง ฉันใช้ namecheap + heroku เป็นการส่วนตัว เคล็ดลับสำหรับผมคือการสร้างไฟล์ .crt cat yourcertificate.crt bundle.ca-bundle > server.crtหนึ่งที่มี ฉันเปิดไฟล์นี้และเพิ่มบรรทัดใหม่หลังจากใบรับรองแรก คุณสามารถอ่านเพิ่มเติมได้ที่

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


ข้อผิดพลาดนี้ส่วนใหญ่จะอยู่ในสภาพแวดล้อมท้องถิ่นไม่ใช่ในการผลิตดังนั้นหากคุณอยู่ในพื้นที่ให้ทำ: process.env ['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
Vivex

@Vivex - มันไม่โอเคที่จะทำเช่นนั้นในสภาพแวดล้อมท้องถิ่นหากประเด็นทั้งหมดคือการทดสอบว่า SSL certs ของคุณทำงานอย่างไรและวิธีการส่งผ่าน ...
dwanderson

2

เพียงแค่ใส่ที่นี่ในกรณีที่มันช่วยใครบางคนคดีของฉันแตกต่างและแปลกไปเล็กน้อย ฉันได้รับสิ่งนี้ตามคำขอที่เข้าถึงได้ผ่านsuperagent - ปัญหาไม่มีอะไรเกี่ยวข้องกับใบรับรอง (ซึ่งติดตั้งอย่างถูกต้อง) และทั้งหมดเกี่ยวข้องกับความจริงที่ว่าฉันได้ผ่านผลลัพธ์ superagent ผ่านการเรียกกลับของโมดูลasync วิธีแก้ไข: แทนที่จะส่งผลลัพธ์ทั้งหมดเพียงแค่result.bodyผ่านการติดต่อกลับของน้ำตก


2

ฉันมีปัญหาเดียวกัน ฉันได้ติดตาม @ThomasReggi และ @ CoolAJ86 โซลูชันแล้วและทำงานได้ดี แต่ฉันไม่พอใจกับวิธีแก้ปัญหา

เนื่องจากเกิดปัญหา "UNABLE_TO_VERIFY_LEAF_SIGNATURE" เนื่องจากระดับการกำหนดค่าการรับรอง

ฉันยอมรับโซลูชัน @thirdender แต่มีการแก้ปัญหาบางส่วนตามเว็บไซต์ทางการของnginxพวกเขากล่าวถึงใบรับรองที่ชัดเจนว่าควรเป็นการรวมกันของใบรับรองเซิร์ฟเวอร์และใบรับรองเชน

ป้อนคำอธิบายรูปภาพที่นี่


2

คุณสามารถลองโดยการตั้งค่าเข้มงวด SSLเป็นfalseดังนี้:

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

มันจะทำงานถ้าการส่งจากแอปพลิเคชัน Node JS ของคุณยอดเยี่ยม !!
Ally Makongo

0

ฉันมีปัญหากับการกำหนดค่า Apache หลังจากติดตั้งใบรับรอง GoDaddy ในโดเมนย่อย ตอนแรกฉันคิดว่ามันอาจเป็นปัญหากับโหนดที่ไม่ได้ส่ง Server Name Indicator (SNI) แต่นั่นไม่ใช่กรณี การวิเคราะห์ใบรับรอง SSL โดเมนย่อยที่มีhttps://www.ssllabs.com/ssltest/กลับข้อผิดพลาดปัญหาเครือ: ไม่สมบูรณ์

หลังจากเพิ่มgd_bundle-g2-g1.crtไฟล์GoDaddy ที่ให้ไว้ผ่านทางSSLCertificateChainFileคำสั่งของ Apache โหนดก็สามารถเชื่อมต่อผ่าน HTTPS และข้อผิดพลาดก็หายไป


0

คุณต้องรวมใบรับรองระดับกลางในเซิร์ฟเวอร์ของคุณ สิ่งนี้จะแก้ไข [ข้อผิดพลาด: UNABLE_TO_VERIFY_LEAF_SIGNATURE]


0

อีกวิธีในการแก้ปัญหานี้อย่างปลอดภัยคือใช้โมดูลต่อไปนี้

node_extra_ca_certs_mozilla_bundle

โมดูลนี้สามารถทำงานได้โดยไม่ต้องแก้ไขรหัสใด ๆ โดยการสร้างไฟล์ PEM ที่มีใบรับรองระดับรากและระดับกลางทั้งหมดที่ Mozilla เชื่อถือได้ คุณสามารถใช้ตัวแปรสภาพแวดล้อมต่อไปนี้ (ใช้ได้กับ 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

หมายเหตุ: ฉันเป็นผู้เขียนโมดูลข้างต้น


0

หากคุณมาที่เธรดนี้เนื่องจากคุณใช้โหนด postgres / pg โมดูลจะมีทางออกที่ดีกว่าการตั้งค่าNODE_TLS_REJECT_UNAUTHORIZEDหรือrejectUnauthorizedซึ่งจะนำไปสู่การเชื่อมต่อที่ไม่ปลอดภัย

ให้กำหนดค่าตัวเลือก "ssl" แทนเพื่อให้ตรงกับพารามิเตอร์สำหรับ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
}

ผมเคยเขียนโมดูลเพื่อความช่วยเหลือเกี่ยวกับการแยกตัวเลือกเหล่านี้จากตัวแปรสภาพแวดล้อมเช่นPGSSLROOTCERT, PGSSLCERTและPGSSLKEY:

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


-1

คำสั่งต่อไปนี้ทำงานให้ฉัน:

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

ปัญหาคือคุณพยายามติดตั้งโมดูลจากที่เก็บที่มีใบรับรอง SSL [Secure Sockets Layer] ที่ไม่ดีหรือไม่น่าเชื่อถือ เมื่อคุณล้างแคชแล้วปัญหานี้จะได้รับการแก้ไขคุณอาจต้องเปลี่ยนเป็นจริงในภายหลัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.