Guide 開髮指南

fibjs 中X509 憑證的使用

背景介紹

什麼是x509 證書

x509 憑證是基於國際標準的公鑰認證服務(PKI)體系中,最常用的一種數位憑證格式。它能夠用於認證和加密,在互聯網上廣泛應用於SSL/TLS 協定以及其他類型的網路應用。 x509 憑證採用了公鑰/私鑰認證機制,並且能夠保證資料傳輸的保密性、完整性和真實性等。

x509 證書在什麼場景中用到

在互聯網上,x509 憑證最常用的場景是用於TLS/SSL 協定中的憑證認證,確保客戶端與服務端之間傳輸的資料使用安全通道進行加密並且是經過驗證的。 x509 憑證也可以用於VPN/SSH 等基於公私鑰加密的應用程式協定中的身份認證。

fibjs 支援x509 憑證的處理

fibjs 支援x509 憑證的處理,提供了crypto 模組中的X509Cert、X509Req 等類別來進行憑證的讀取、建立和簽章等操作。可以透過這些類別取得憑證的有效期限、公鑰、頒發者、主題名稱等信息,以及對憑證進行簽署、驗證等操作。同時,fibjs 也提供了HttpsServer 類別來支援HTTPS 的憑證認證和加密連接,使得在fibjs 中使用x509 憑證變得更加容易。

X509 模組的介紹

X509 模組是什麼

在fibjs 的crypto 模組中,提供了X509Cert、X509Req 等類別來進行x509 憑證的讀取、建立和簽署等操作。 X509 模組是一個用於處理x509 憑證的模組,提供了對憑證的解析、建立和驗證等操作。

X509 模組的作用

X509 模組的作用是對x509 證書進行操作,可以透過此模組讀取現有的x509 證書,取得證書的有效期限、公鑰、頒發者、主題名稱等資訊。同時, X509 模組也可以建立x509 憑證要求和簽章證書,方式如用於TLS/SSL 協定中的憑證認證。

X509 模組的API

以下是X509 模組中比較重要的API 清單:

  • X509Cert: 用於讀取和操作x509 憑證的類別。
  • X509Req: 用於建立x509 憑證請求的類別。
  • verify: 透過CA 憑證對驗證x509 憑證。
  • SslServer: 提供基於x509 證書的認證服務的類別。
  • SslSocket: 提供基於x509 憑證的認證服務的套接字收發資料操作的類別。

範例程式碼

以下是讀取x509 憑證和建立x509 憑證請求的範例程式碼:

1 2 3 4 5 6 7 8 9 10 11 12
const crypto = require('crypto'); // load the cert const cert = crypto.loadCert('server.crt'); console.log(cert.subject); // create x509 certificate request let pky = crypto.PKey.from(private_pem); let req = new crypto.X509Req("CN=localhost,O=fibjs", pky); let derReq = req.der(); let pemReq = req.pem(); console.log(pemReq);

以上範例程式碼透過X509Cert 類別讀取了一個現有的x509 證書,並輸出了證書的主題名稱subject。同時,範例程式碼也示範如何透過X509Req 建立x509 憑證請求,並輸出了PEM 格式的請求資訊。

X509 模組的使用

產生自簽名憑證

產生自簽名憑證的過程比較簡單,一般需要完成以下步驟:

  • 產生PKey(私鑰)
  • 產生X509Req(憑證請求)
  • 使用X509Req 產生X509Cert(正式憑證)
  • 儲存證書

透過這些步驟,可以自行產生一個用於測試和開發環境的x509 憑證。以下是具體的實作:

使用以下程式碼建立PKey 物件。其中,from() 方法可以透過一個PEM 格式的字串或一個Buffer 來建立PKey 物件。

1 2
const crypto = require('crypto'); const pky = crypto.PKey.from(private_pem);

使用以下程式碼建立X509Req 物件。其中,X509Req 的第一個參數是主題可分辨名稱(Subject Name),字串格式為key1=value1,key2=value2。第二個參數是先前建立的PKey 對象,用於憑證簽章。例如:

1
let xrq = new crypto.X509Req("CN=localhost,O=fibjs", pky);

使用以下程式碼建立X509Cert(正式證書)。具體操作是呼叫X509Req 的sign() 方法,該方法接受三個參數:憑證授權單位的名稱、用於簽署的PKey 物件、以及其他相關資訊。例如,在下列範例中,將X509Req 物件簽署為自簽名證書,簽章機構為本身,證書有效期限為10 年:

1 2 3 4 5
const opt = { notBefore: new Date(), notAfter: new Date(new Date().getTime() + 10 * 365 * 24 * 60 * 60 * 1000) }; const cert = xrq.sign("CN=localhost,O=fibjs", pky, opt);

使用以下程式碼將PKey 和X509Cert 儲存到本機檔案。由於憑證是使用PEM 格式儲存的,因此可以使用pem() 方法將憑證物件轉換為字串,然後直接儲存到檔案中:

1 2 3 4 5
const fs = require('fs'); const ks = pky.pem(); // export pem format data of the private key const cs = cert.pem(); // export pem format data of the cert fs.writeFile('mycert.key', ks); // save the key fs.writeFile('mycert.pem', cs); // save the cert

以上程式碼完成了從產生私鑰到儲存自簽名憑證的整個過程。可以透過這個憑證來測試和開發安全相關的應用程式。

載入證書

載入憑證是使用x509 憑證時的一項重要操作。以下介紹如何載入憑證檔案和載入公鑰私鑰。

為了使用x509 證書,必須先將證書檔案讀取到記憶體中,並將其轉換為x509 證書物件。以下是如何載入證書檔案的步驟:

在fibjs 的JavaScript 程式中,可以使用fs 模組的相關API 來讀取檔案。例如,使用以下程式碼讀取PEM 格式的憑證檔案:

1 2
const fs = require('fs'); const certData = fs.readFile('server.crt');

讀取檔案後,必須使用X509Cert 物件將憑證檔案內容轉換為x509 憑證:

1 2
const crypto = require('crypto'); const cert = new crypto.X509Cert(certData);

經過以上步驟,可以載入本地的x509 憑證檔案。也可以使用crypto.loadCert 直接讀取憑證:

1 2
const crypto = require('crypto'); const cert = crypto.loadCert('server.crt');

x509 憑證中保存著公鑰和加密後的簽章訊息,因此需要在使用憑證時,將憑證中的公鑰解析出來,以方便對資料進行加密和解密。 PKey 類別可以將PEM 格式的公鑰/私鑰字串轉換為公鑰/私鑰物件。可以使用以下程式碼讀取PEM 格式的公鑰/私鑰字串,並建立PKey 物件:

1 2
const privateKey = fs.readFile('private.pem'); // load the data from file const pKey = crypto.PKey.from(privateKey); // load from pem format data

或使用crypto.loadPKey 直接讀取:

1 2
const crypto = require('crypto'); const pKey = crypto.loadPKey('private.pem');

經過以上步驟,可以將公鑰/私鑰檔案轉換為PKey 物件。

解析憑證

憑證是SSL/TLS 互動中重要的組成部分,用於身份驗證和資料傳輸的加密。現在,我們來了解如何在fibjs 中解析一個憑證。

我們可以使用crypto 模組的X509Cert 類,透過讀取一個DER/PEM 格式的憑證檔案建立一個憑證對象,緊接著可以取得憑證的一些基本信息,例如取得憑證的主題名稱、頒發者名稱、有效期限等等訊息。

範例程式碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
const crypto = require('crypto'); const cert = crypto.loadCert('path/to/cert.pem'); const subjectName = cert.subject; const issuerName = cert.issuer; const validFromDate = cert.notBefore; const expirationDate = cert.notAfter; const serialNumber = cert.serial; console.log(`证书主题名称: ${subjectName}`); console.log(`证书颁发者名称: ${issuerName}`); console.log(`证书有效期: ${validFromDate.toLocaleString()} ~ ${expirationDate.toLocaleString()}`); console.log(`证书序列号: ${serialNumber}`);

當需要使用一個憑證時,我們需要驗證這個憑證的合法性,關鍵是要確定憑證是由一個可信任的組織頒發的。可以使用X509Cert 中的verify 方法來檢查憑證的合法性,常見的驗證方式是透過驗證憑證的鏈,確保憑證被受信任的CA 所頒發。

範例程式碼如下:

1 2 3 4 5 6 7 8 9
const caCert = crypto.loadCert('path/to/ca.crt'); const verifyResult = cert.verify(caCert); if (verifyResult !== 0) { console.error('证书验证失败', verifyResult); } else { console.log('证书验证通过'); }

在此範例程式碼中,我們首先讀取指定的CA 證書,產生一個X509Cert 對象,接著使用證書對像上的verify 方法驗證需要驗證的證書,並取得驗證結果。你可以透過比較驗證結果是否等於0 來判斷憑證是否合法。如果驗證結果不為0,則表示驗證失敗,此時應停止使用該憑證。

使用證書

使用https 伺服器時,需要確保使用的憑證已新增至伺服器。以下是一個簡單的範例,透過crypto 模組載入憑證和私鑰檔案:

1 2 3 4 5 6 7 8 9 10
const http = require("http"); const crypto = require("crypto"); const cert = crypto.loadCert("server.crt"); const key = crypto.loadPKey("server.key"); const server = new http.HttpsServer(cert, key, 8443, function(req) { req.response.write(`Hello, fibjs!`); }); server.start();

在上面的範例中,我們透過loadCert 和loadPKey 函數載入了server.crt 和server.key 文件,然後使用HttpsServer 物件建立了一個服務,並用載入的憑證和金鑰檔案啟動服務。

X509 模組的注意事項

憑證的安全性

X509 模組提供了憑證的建立、處理等功能,憑證的安全性必須得到保障,這需要特別注意以下幾點:

  • 私鑰的安全性。私鑰是憑證的重要組成部分,必須嚴格保護。在憑證的使用過程中,應該盡可能地將私鑰儲存在安全的地方,並合理地設定存取權限。
  • 證書的傳輸安全。在憑證的交換和使用過程中,必須採用安全的傳輸方式,避免憑證被竊取或竄改。
  • 證書的驗證安全性。證書驗證是確保證書有效且安全性的重要環節,必須嚴格遵守證書的驗證規則來驗證,以避免偽造的證書誤導使用者。

證書的有效期限

憑證的有效期限是指從憑證發行日期到憑證過期日期之間的這段時間。證書的有效期限限制了證書的使用時間,在證書過期之前,證書持有人可以使用證書,但在證書過期之後,證書將失去其有效性。

因此,在使用憑證之前,必須先檢查憑證的有效期,以避免使用已過期的憑證。同時,在證書過期之前,應儘早更新證書,以確保證書的可用性。

憑證的信任機制

憑證的信任機制是憑證能否被客戶端或伺服器端信任的關鍵因素。通常情況下,客戶端或伺服器端只信任由可信任機構(CA)簽發和承認的憑證。

在使用憑證之前,必須確定憑證的信任問題。可以透過檢查憑證的頒發機構、憑證的主題可分辨名稱等方式來判斷憑證是否可信任。

憑證的更新機制

憑證的更新機制是確保憑證一直有效且安全的重要環節。通常情況下,證書的更新主要包括兩個方面:

  • 證書過期後的更新。在證書過期後,必須重新申請證書,並按照相應的規則進行簽署和驗證,以確保證書的有效性。
  • 證書擴充和更新。在證書的使用過程中,如果需要擴展或更新證書的信息,可以透過重新申請證書並進行簽名和驗證的方式來實現。

綜上所述,X509 模組提供了憑證的建立、處理等功能,是確保憑證安全、可信任和有效的重要環節。在使用和管理證書的過程中,必須遵循相應的規則和要求,以確保證書的有效性和安全性。

👉 【新增native 模組