TLS (SSL)#

穩定性:2 - 穩定

原始碼: lib/tls.js

node:tls 模組提供建立在 OpenSSL 之上的傳輸層安全性 (TLS) 和安全通訊協定層 (SSL) 協定的實作。可以使用以下方式存取此模組

const tls = require('node:tls'); 

判斷是否不支援加密#

Node.js 有可能在建置時不包含對 node:crypto 模組的支援。在這種情況下,嘗試從 tls import 或呼叫 require('node:tls') 會導致擲回錯誤。

使用 CommonJS 時,可以使用 try/catch 捕捉擲回的錯誤

let tls;
try {
  tls = require('node:tls');
} catch (err) {
  console.error('tls support is disabled!');
} 

當使用詞彙 ESM import 關鍵字時,只有在嘗試載入模組之前(例如,使用預載模組)註冊 process.on('uncaughtException') 處理常式時,才能捕捉錯誤。

當使用 ESM 時,如果程式碼有可能在未啟用加密支援的 Node.js 版本上執行,請考慮使用 import() 函式,而不是詞彙 import 關鍵字

let tls;
try {
  tls = await import('node:tls');
} catch (err) {
  console.error('tls support is disabled!');
} 

TLS/SSL 概念#

TLS/SSL 是一組協定,依賴公鑰基礎架構 (PKI) 來啟用客戶端與伺服器之間的安全通訊。對於大多數常見情況,每個伺服器都必須有一個私人金鑰。

私人金鑰可以用多種方式產生。以下範例說明如何使用 OpenSSL 命令列介面產生 2048 位元 RSA 私人金鑰

openssl genrsa -out ryans-key.pem 2048 

使用 TLS/SSL 時,所有伺服器(以及一些客戶端)都必須有「憑證」。憑證是對應於私人金鑰的「公鑰」,並且由憑證授權機構或私人金鑰的所有者數位簽署(此類憑證稱為「自簽署」)。取得憑證的第一步是建立「憑證簽署要求」(CSR) 檔案。

OpenSSL 命令列介面可用于為私人金鑰產生 CSR

openssl req -new -sha256 -key ryans-key.pem -out ryans-csr.pem 

產生 CSR 檔案後,可以將其傳送給憑證授權機構簽署,或用於產生自簽署憑證。

以下範例說明如何使用 OpenSSL 命令列介面建立自簽署憑證

openssl x509 -req -in ryans-csr.pem -signkey ryans-key.pem -out ryans-cert.pem 

產生憑證後,可用於產生 .pfx.p12 檔案

openssl pkcs12 -export -in ryans-cert.pem -inkey ryans-key.pem \
      -certfile ca-cert.pem -out ryans.pfx 

其中

  • in:為已簽署憑證
  • inkey:為關聯的私密金鑰
  • certfile:為將所有憑證授權機構 (CA) 憑證串接成單一檔案,例如 cat ca1-cert.pem ca2-cert.pem > ca-cert.pem

完美向前保密#

術語向前保密完美向前保密描述金鑰協商 (即金鑰交換) 方法的功能。也就是說,伺服器和用戶端金鑰用於協商新的暫時金鑰,這些金鑰專門且僅用於目前的通訊階段。實際上,這表示即使伺服器的私密金鑰遭到入侵,通訊也只有在攻擊者設法取得專門為該階段產生的金鑰對時,才能被竊聽者解密。

完美向前保密是透過在每次 TLS/SSL 交握時,隨機產生金鑰對進行金鑰協商(與對所有階段使用相同金鑰相反)來達成。實作此技術的方法稱為「暫時性」。

目前通常使用兩種方法來達成完美向前保密(請注意傳統縮寫中附加的字元「E」)

  • ECDHE:橢圓曲線 Diffie-Hellman 金鑰協定協定的暫時性版本。
  • DHE:Diffie-Hellman 金鑰協定協定的暫時性版本。

預設啟用使用 ECDHE 的完美轉發保密。建立 TLS 伺服器時,可以使用 ecdhCurve 選項自訂要使用的 ECDH 曲線清單。請參閱 tls.createServer() 以取得更多資訊。

預設停用 DHE,但可以將 dhparam 選項設定為 'auto',與 ECDHE 一併啟用。也支援自訂 DHE 參數,但建議使用自動選取的已知參數。

完美轉發保密在 TLSv1.2 之前是選用的。從 TLSv1.3 開始,(EC)DHE 永遠使用(PSK-only 連線除外)。

ALPN 和 SNI#

ALPN(應用程式層協定協商擴充功能)和 SNI(伺服器名稱指示)是 TLS 交握擴充功能

  • ALPN:允許一個 TLS 伺服器用於多個協定(HTTP、HTTP/2)
  • SNI:允許一個 TLS 伺服器用於多個具有不同憑證的主機名稱。

預先共用金鑰#

TLS-PSK 支援可用作一般憑證為基礎的驗證的替代方案。它使用預先共用金鑰而非憑證來驗證 TLS 連線,提供雙向驗證。TLS-PSK 和公開金鑰基礎架構並非互斥。用戶端和伺服器可以容納兩者,在一般密碼協商步驟中選擇其中之一。

TLS-PSK 僅在有方法安全地與每部連線機器共用金鑰時才是一個好選擇,因此它並未取代大多數 TLS 用途的公開金鑰基礎架構 (PKI)。OpenSSL 中的 TLS-PSK 實作在最近幾年出現許多安全漏洞,主要是因為它僅由少數應用程式使用。請在切換至 PSK 加密法之前考量所有其他替代方案。產生 PSK 時,使用足夠的熵非常重要,如 RFC 4086 所述。從密碼或其他低熵來源衍生共用密碼並不安全。

PSK 加密法預設為停用,因此使用 TLS-PSK 必須透過 ciphers 選項明確指定加密套件。可透過 openssl ciphers -v 'PSK' 擷取可用加密法的清單。所有 TLS 1.3 加密法都符合 PSK 資格,且可透過 openssl ciphers -v -s -tls1_3 -psk 擷取。

根據 RFC 4279,長度達 128 位元組的 PSK 身分和長度達 64 位元組的 PSK 必須獲得支援。自 OpenSSL 1.1.0 起,最大身分大小為 128 位元組,最大 PSK 長度為 256 位元組。

目前的實作不支援非同步 PSK 回呼,因為基礎 OpenSSL API 有其限制。

用戶端發起的重新協商攻擊緩解#

TLS 協定允許用戶端重新協商 TLS 會話的某些面向。很不幸地,會話重新協商需要不成比例的伺服器端資源,使其成為阻斷服務攻擊的潛在媒介。

為了降低風險,重新協商每 10 分鐘限制為 3 次。當超過此臨界值時,會在 tls.TLSSocket 執行個體上發出 'error' 事件。這些限制是可組態的

  • tls.CLIENT_RENEG_LIMIT <number> 指定重新協商要求的次數。預設:3
  • tls.CLIENT_RENEG_WINDOW <number> 指定重新協商視窗(以秒為單位)。預設:600(10 分鐘)。

在未充分了解影響和風險的情況下,不應修改預設重新協商限制。

TLSv1.3 不支援重新協商。

會話復原#

建立 TLS 會話可能會相對緩慢。可以透過儲存並稍後重複使用會話狀態來加速此程序。有數種機制可以這樣做,在此從最舊到最新(且優先)進行討論。

會話識別碼#

伺服器會為新連線產生一個唯一 ID,並將其傳送給用戶端。用戶端和伺服器會儲存會話狀態。在重新連線時,用戶端會傳送其已儲存會話狀態的 ID,如果伺服器也擁有該 ID 的狀態,則可以同意使用它。否則,伺服器將建立新的會話。請參閱 RFC 2246 以取得更多資訊,第 23 頁和第 30 頁。

大多數網路瀏覽器在提出 HTTPS 要求時,都支援使用會話識別碼進行復原。

對於 Node.js,用戶端會等到 'session' 事件取得會話資料,並提供資料給後續 tls.connect()session 選項,以重複使用會話。伺服器必須實作 'newSession''resumeSession' 事件的處理常式,以使用會話 ID 作為查詢金鑰來儲存和復原會話資料,以重複使用會話。若要跨負載平衡器或叢集工作站重複使用會話,伺服器必須在其會話處理常式中使用共用會話快取(例如 Redis)。

會話票證#

伺服器會對整個階段狀態進行加密,並以「票證」的形式傳送給用戶端。重新連線時,狀態會在初始連線中傳送給伺服器。此機制避免了伺服器端階段快取的需要。如果伺服器因為任何原因(無法解密、過舊等)而未採用票證,它會建立新的階段並傳送新的票證。請參閱 RFC 5077 以取得更多資訊。

許多網路瀏覽器在執行 HTTPS 要求時,都開始普遍支援使用階段票證進行恢復。

對於 Node.js,用戶端使用與階段識別碼恢復相同的 API,以進行階段票證恢復。進行除錯時,如果 tls.TLSSocket.getTLSTicket() 傳回值,表示階段資料包含票證,否則表示包含用戶端階段狀態。

對於 TLSv1.3,請注意伺服器可能會傳送多個票證,導致多個 'session' 事件,請參閱 'session' 以取得更多資訊。

單一程序伺服器不需要任何特定實作即可使用階段票證。若要在伺服器重新啟動或負載平衡器之間使用階段票證,所有伺服器都必須擁有相同的票證金鑰。內部有三個 16 位元組金鑰,但 tls API 會將它們顯示為單一 48 位元組緩衝區,以方便使用。

可以呼叫 server.getTicketKeys() 在一個伺服器執行個體上取得票證金鑰,然後進行分發,但更合理的做法是安全產生 48 位元組的安全亂數資料,並使用 tls.createServer()ticketKeys 選項設定它們。應定期重新產生金鑰,而且可以使用 server.setTicketKeys() 重設伺服器的金鑰。

階段性票證金鑰為密碼學金鑰,且必須安全地儲存。對於 TLS 1.2 及以下版本,如果這些金鑰遭到入侵,則使用這些金鑰加密的所有階段性票證都可能遭到解密。這些金鑰不應儲存在磁碟中,且應定期重新產生。

如果客戶端宣告支援階段性票證,伺服器將會傳送這些票證。伺服器可以透過在 secureOptions 中提供 require('node:constants').SSL_OP_NO_TICKET 來停用階段性票證。

階段性識別碼和階段性票證都會逾時,導致伺服器建立新的階段性。逾時時間可以使用 tls.createServer()sessionTimeout 選項設定。

對於所有機制,當恢復失敗時,伺服器將建立新的階段性。由於恢復階段性失敗並不會導致 TLS/HTTPS 連線失敗,因此很容易忽略不必要的 TLS 效能不佳問題。OpenSSL CLI 可用於驗證伺服器是否正在恢復階段性。使用 -reconnect 選項搭配 openssl s_client,例如

openssl s_client -connect localhost:443 -reconnect 

讀取偵錯輸出。例如,第一個連線應顯示「New」

New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 

後續連線應顯示「Reused」,例如

Reused, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 

修改預設 TLS 加密套件#

Node.js 建置時會套用預設的已啟用和已停用 TLS 加密套件。這個預設加密清單可以在建置 Node.js 時設定,以允許發行版提供自己的預設清單。

可以使用下列指令顯示預設加密套件

node -p crypto.constants.defaultCoreCipherList | tr ':' '\n'
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES256-GCM-SHA384
DHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-SHA256
DHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA384
DHE-RSA-AES256-SHA384
ECDHE-RSA-AES256-SHA256
DHE-RSA-AES256-SHA256
HIGH
!aNULL
!eNULL
!EXPORT
!DES
!RC4
!MD5
!PSK
!SRP
!CAMELLIA 

這個預設值可以使用 --tls-cipher-list 命令列開關(直接或透過 NODE_OPTIONS 環境變數)完全取代。例如,以下指令會將 ECDHE-RSA-AES128-GCM-SHA256:!RC4 設定為預設的 TLS 加密套件

node --tls-cipher-list='ECDHE-RSA-AES128-GCM-SHA256:!RC4' server.js

export NODE_OPTIONS=--tls-cipher-list='ECDHE-RSA-AES128-GCM-SHA256:!RC4'
node server.js 

若要驗證,請使用以下指令顯示設定的加密套件清單,注意 defaultCoreCipherListdefaultCipherList 之間的差異

node --tls-cipher-list='ECDHE-RSA-AES128-GCM-SHA256:!RC4' -p crypto.constants.defaultCipherList | tr ':' '\n'
ECDHE-RSA-AES128-GCM-SHA256
!RC4 

也就是說,defaultCoreCipherList 清單是在編譯時設定,而 defaultCipherList 則是在執行時設定。

若要從執行時間內修改預設的加密套件,請修改 tls.DEFAULT_CIPHERS 變數,這必須在監聽任何 socket 之前執行,否則不會影響已開啟的 socket。例如

// Remove Obsolete CBC Ciphers and RSA Key Exchange based Ciphers as they don't provide Forward Secrecy
tls.DEFAULT_CIPHERS +=
  ':!ECDHE-RSA-AES128-SHA:!ECDHE-RSA-AES128-SHA256:!ECDHE-RSA-AES256-SHA:!ECDHE-RSA-AES256-SHA384' +
  ':!ECDHE-ECDSA-AES128-SHA:!ECDHE-ECDSA-AES128-SHA256:!ECDHE-ECDSA-AES256-SHA:!ECDHE-ECDSA-AES256-SHA384' +
  ':!kRSA'; 

預設值也可以使用 tls.createSecureContext() 中的 ciphers 選項針對每個客戶端或伺服器替換,此選項也在 tls.createServer()tls.connect() 中提供,以及在建立新的 tls.TLSSocket 時提供。

加密套件清單可以包含 TLSv1.3 加密套件名稱(以 'TLS_' 開頭)和 TLSv1.2 及以下版本加密套件的規範。TLSv1.2 加密套件支援舊版規範格式,請參閱 OpenSSL 加密套件清單格式 文件以取得詳細資訊,但這些規範適用於 TLSv1.3 加密套件。TLSv1.3 套件只能透過在加密套件清單中包含其完整名稱來啟用。例如,它們無法使用舊版 TLSv1.2 'EECDH''!EECDH' 規範來啟用或停用。

儘管 TLSv1.3 和 TLSv1.2 加密套件的相對順序,但 TLSv1.3 協定比 TLSv1.2 安全得多,如果交握指示支援 TLSv1.3 協定,並且啟用了任何 TLSv1.3 加密套件,它將始終優先於 TLSv1.2。

Node.js 內含的預設加密組件經過仔細挑選,以反映當前的安全性最佳實務和風險緩解。變更預設加密組件會對應用程式的安全性產生重大影響。--tls-cipher-list 切換和 ciphers 選項應僅在絕對必要時使用。

預設加密組件偏好 Chrome 的「現代密碼學」設定 的 GCM 加密組件,同時也偏好 ECDHE 和 DHE 加密組件以實現完美前向保密,同時提供一些向後相容性。

仰賴不安全且已棄用的 RC4 或 DES 為基礎的加密組件的舊客戶端(例如 Internet Explorer 6)無法與預設組態完成交握程序。如果必須支援這些客戶端,TLS 建議 可以提供相容的加密組件。有關格式的更多詳細資訊,請參閱 OpenSSL 加密組件清單格式 文件。

只有五個 TLSv1.3 加密組件

  • 'TLS_AES_256_GCM_SHA384'
  • 'TLS_CHACHA20_POLY1305_SHA256'
  • 'TLS_AES_128_GCM_SHA256'
  • 'TLS_AES_128_CCM_SHA256'
  • 'TLS_AES_128_CCM_8_SHA256'

前三個預設啟用。兩個基於 CCM 的組件由 TLSv1.3 支援,因為它們在受限系統上效能可能較佳,但它們並未預設啟用,因為它們提供的安全性較低。

X509 憑證錯誤碼#

多個函式可能會因 OpenSSL 回報的憑證錯誤而失敗。在這種情況下,函式會透過其回呼提供一個 <Error>,其具有 code 屬性,該屬性可以採用下列值之一

  • 'UNABLE_TO_GET_ISSUER_CERT':無法取得發行者憑證。
  • 'UNABLE_TO_GET_CRL':無法取得憑證 CRL。
  • 'UNABLE_TO_DECRYPT_CERT_SIGNATURE':無法解密憑證的簽章。
  • 'UNABLE_TO_DECRYPT_CRL_SIGNATURE':無法解密 CRL 的簽章。
  • 'UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY':無法解碼發行者公開金鑰。
  • 'CERT_SIGNATURE_FAILURE':憑證簽章失敗。
  • 'CRL_SIGNATURE_FAILURE':CRL 簽章失敗。
  • 'CERT_NOT_YET_VALID':憑證尚未有效。
  • 'CERT_HAS_EXPIRED':憑證已過期。
  • 'CRL_NOT_YET_VALID':CRL 尚未有效。
  • 'CRL_HAS_EXPIRED':CRL 已過期。
  • 'ERROR_IN_CERT_NOT_BEFORE_FIELD':憑證的 notBefore 欄位格式錯誤。
  • 'ERROR_IN_CERT_NOT_AFTER_FIELD':憑證的 notAfter 欄位格式錯誤。
  • 'ERROR_IN_CRL_LAST_UPDATE_FIELD':CRL 的 lastUpdate 欄位格式錯誤。
  • 'ERROR_IN_CRL_NEXT_UPDATE_FIELD':CRL 的 nextUpdate 欄位格式錯誤。
  • 'OUT_OF_MEM':記憶體不足。
  • 'DEPTH_ZERO_SELF_SIGNED_CERT':自簽憑證。
  • 'SELF_SIGNED_CERT_IN_CHAIN':憑證鏈中存在自簽憑證。
  • 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY':無法取得本機發行者憑證。
  • 'UNABLE_TO_VERIFY_LEAF_SIGNATURE':無法驗證第一個憑證。
  • 'CERT_CHAIN_TOO_LONG':憑證鏈太長。
  • 'CERT_REVOKED':憑證已撤銷。
  • 'INVALID_CA':無效的 CA 憑證。
  • 'PATH_LENGTH_EXCEEDED':路徑長度限制已超過。
  • 'INVALID_PURPOSE':不支援的憑證用途。
  • 'CERT_UNTRUSTED':憑證不受信任。
  • 'CERT_REJECTED':憑證被拒絕。
  • 'HOSTNAME_MISMATCH':主機名稱不符。

類別:tls.CryptoStream#

穩定性:0 - 已棄用:請改用 tls.TLSSocket

tls.CryptoStream 類別表示一個加密資料串流。此類別已棄用,不應再使用。

cryptoStream.bytesWritten#

cryptoStream.bytesWritten 屬性傳回寫入底層 socket 的總位元組數,包括實作 TLS 協定的所需位元組。

類別:tls.SecurePair#

穩定性:0 - 已棄用:請改用 tls.TLSSocket

tls.createSecurePair() 傳回。

事件:'secure'#

一旦建立安全連線,SecurePair 物件就會發出 'secure' 事件。

與檢查伺服器 'secureConnection' 事件一樣,應檢查 pair.cleartext.authorized 以確認所使用的憑證是否已正確授權。

類別:tls.Server#

使用 TLS 或 SSL 接受加密連線。

事件:'connection'#

在 TLS 交握開始之前,當建立新的 TCP 串流時,就會發出此事件。socket 通常是 net.Socket 類型的物件,但不會收到事件,這與從 net.Server 'connection' 事件建立的 socket 不同。通常使用者不會想要存取此事件。

使用者也可以明確發出此事件,以將連線注入 TLS 伺服器。在這種情況下,可以傳遞任何 Duplex 串流。

事件:'keylog'#

  • line <Buffer> NSS SSLKEYLOGFILE 格式的 ASCII 文字行。
  • tlsSocket <tls.TLSSocket> 產生事件的 tls.TLSSocket 執行個體。

當連線到此伺服器時,會產生 keylog 事件(通常在握手完成前,但並非一定)。此金鑰材料可以儲存以進行除錯,因為它允許解密擷取的 TLS 流量。它可能會針對每個 socket 發出多次。

典型的使用案例是將接收到的行附加到共用文字檔案,該檔案稍後會由軟體(例如 Wireshark)用來解密流量

const logFile = fs.createWriteStream('/tmp/ssl-keys.log', { flags: 'a' });
// ...
server.on('keylog', (line, tlsSocket) => {
  if (tlsSocket.remoteAddress !== '...')
    return; // Only log keys for a particular IP
  logFile.write(line);
}); 

事件:'newSession'#

在建立新的 TLS 會話時,會發出 'newSession' 事件。這可以用於將會話儲存在外部儲存體中。資料應提供給 'resumeSession' 回呼。

呼叫時,監聽器回呼會傳遞三個參數

  • sessionId <Buffer> TLS 會話識別碼
  • sessionData <Buffer> TLS 會話資料
  • callback <Function> 不帶參數的回呼函式,必須呼叫才能透過安全連線傳送或接收資料。

僅在加入事件監聽器後建立的連線,才會受到監聽此事件的影響。

事件:'OCSPRequest'#

當用戶端傳送憑證狀態要求時,會發出 'OCSPRequest' 事件。呼叫監聽器回呼時,會傳遞三個參數

  • certificate <Buffer> 伺服器憑證
  • issuer <Buffer> 簽發者憑證
  • callback <Function> 必須呼叫的回呼函數,以提供 OCSP 要求的結果。

可以剖析伺服器的目前憑證以取得 OCSP URL 和憑證 ID;取得 OCSP 回應後,會呼叫 callback(null, resp),其中 resp 是包含 OCSP 回應的 Buffer 執行個體。certificateissuer 都是主憑證和簽發者憑證的 DER Buffer 表示。這些可用於取得 OCSP 憑證 ID 和 OCSP 端點 URL。

或者,可以呼叫 callback(null, null),表示沒有 OCSP 回應。

呼叫 callback(err) 會導致呼叫 socket.destroy(err)

OCSP 要求的典型流程如下

  1. 用戶端連線到伺服器並傳送 'OCSPRequest'(透過 ClientHello 中的狀態資訊擴充)。
  2. 伺服器收到要求,並發出 'OCSPRequest' 事件,如果已註冊,則呼叫監聽器。
  3. 伺服器從 certificateissuer 萃取 OCSP URL,並對 CA 執行 OCSP 要求
  4. 伺服器從 CA 收到 'OCSPResponse',並透過 callback 參數傳送回用戶端
  5. 用戶端驗證回應,並終止 socket 或執行交握。

如果憑證是自簽署的,或發行者不在根憑證清單中,則 issuer 可以為 null。(建立 TLS 連線時,可以透過 ca 選項提供發行者。)

僅在加入事件監聽器後建立的連線,才會受到監聽此事件的影響。

可以使用類似 asn1.js 的 npm 模組來剖析憑證。

事件:'resumeSession'#

當用戶端要求恢復先前的 TLS 會話時,會發出 'resumeSession' 事件。呼叫時,會將兩個參數傳遞給監聽器回呼函式

  • sessionId <Buffer> TLS 會話識別碼
  • callback <Function> 在復原先前會話時呼叫的回呼函式:callback([err[, sessionData]])

事件監聽器應使用指定的 sessionId 在外部儲存體中查詢由 'newSession' 事件處理常式儲存的 sessionData。如果找到,請呼叫 callback(null, sessionData) 以恢復會話。如果找不到,則無法恢復會話。必須呼叫 callback() 而沒有 sessionData,以便握手可以繼續進行,並建立新的會話。可以呼叫 callback(err) 以終止傳入連線並銷毀 socket。

僅在加入事件監聽器後建立的連線,才會受到監聽此事件的影響。

以下說明如何恢復 TLS 會話

const tlsSessionStore = {};
server.on('newSession', (id, data, cb) => {
  tlsSessionStore[id.toString('hex')] = data;
  cb();
});
server.on('resumeSession', (id, cb) => {
  cb(null, tlsSessionStore[id.toString('hex')] || null);
}); 

事件:'secureConnection'#

在成功完成新連線的交握程序後,會發出 'secureConnection' 事件。呼叫時,會將單一參數傳遞給監聽器回呼函式

tlsSocket.authorized 屬性是一個 boolean,表示用戶端是否已由伺服器提供的其中一個憑證授權機構驗證。如果 tlsSocket.authorizedfalse,則會設定 socket.authorizationError 來描述授權失敗的方式。視 TLS 伺服器的設定而定,仍可能會接受未授權的連線。

tlsSocket.alpnProtocol 屬性是一個包含所選 ALPN 協定的字串。當 ALPN 沒有選定的協定,因為用戶端或伺服器沒有傳送 ALPN 擴充功能時,tlsSocket.alpnProtocol 等於 false

tlsSocket.servername 屬性是一個包含透過 SNI 要求的伺服器名稱的字串。

事件:'tlsClientError'#

當在建立安全連線之前發生錯誤時,會發出 'tlsClientError' 事件。呼叫時,會將兩個參數傳遞給監聽器回呼

  • exception <Error> 描述錯誤的 Error 物件
  • tlsSocket <tls.TLSSocket> 發生錯誤的 tls.TLSSocket 執行個體。

server.addContext(hostname, context)#

server.addContext() 方法會新增一個安全內容,如果用戶端要求的 SNI 名稱與提供的 hostname(或萬用字元)相符,則會使用此安全內容。

當有多個匹配的內容時,會使用最近新增的那個。

server.address()#

傳回作業系統報告的伺服器繫結位址、位址家族名稱和連接埠。有關更多資訊,請參閱 net.Server.address()

server.close([callback])#

  • callback <Function> 註冊為監聽伺服器執行個體的 'close' 事件的監聽器回呼函式。
  • 傳回:<tls.Server>

server.close() 方法會停止伺服器接受新連線。

此函式非同步執行。當伺服器沒有更多開放式連線時,會發出 'close' 事件。

server.getTicketKeys()#

  • 傳回:<Buffer> 包含會話票證金鑰的 48 位元組緩衝區。

傳回會話票證金鑰。

有關更多資訊,請參閱 會話續接

server.listen()#

開始伺服器監聽加密連線。此方法與 server.listen()net.Server 相同。

server.setSecureContext(options)#

server.setSecureContext() 方法取代現有伺服器的安全內容。現有的伺服器連線不會中斷。

server.setTicketKeys(keys)#

設定會話票證金鑰。

變更票證金鑰僅對未來的伺服器連線有效。現有的或目前待處理的伺服器連線將使用先前的金鑰。

有關更多資訊,請參閱 會話續接

類別:tls.TLSSocket#

對寫入資料執行透明加密和所有必要的 TLS 協商。

tls.TLSSocket 的執行個體實作雙工 串流 介面。

傳回 TLS 連線中繼資料的方法(例如 tls.TLSSocket.getPeerCertificate())僅在連線開啟時傳回資料。

new tls.TLSSocket(socket[, options])#

  • socket <net.Socket> | <stream.Duplex> 在伺服器端,任何 Duplex 串流。在用戶端,任何 net.Socket 實例(對於用戶端的通用 Duplex 串流支援,必須使用 tls.connect())。
  • options <Object>
    • enableTrace:請參閱 tls.createServer()
    • isServer:SSL/TLS 協定是不對稱的,TLSSockets 必須知道它們是要作為伺服器還是用戶端。如果為 true,TLS socket 將會實例化為伺服器。預設值:false
    • server <net.Server> net.Server 實例。
    • requestCert:是否透過要求憑證來驗證遠端對等端。用戶端總是要求伺服器憑證。伺服器(isServer 為 true)可以將 requestCert 設為 true 以要求用戶端憑證。
    • rejectUnauthorized:請參閱 tls.createServer()
    • ALPNProtocols:請參閱 tls.createServer()
    • SNICallback:請參閱 tls.createServer()
    • session <Buffer> 包含 TLS 會話的 Buffer 實例。
    • requestOCSP <boolean> 如果為 true,指定 OCSP 狀態要求擴充功能將會新增到用戶端 hello,而且在建立安全通訊之前,socket 上會發出 'OCSPResponse' 事件
    • secureContext:使用 tls.createSecureContext() 建立的 TLS 內容物件。如果 沒有 提供 secureContext,將會透過將整個 options 物件傳遞給 tls.createSecureContext() 來建立一個。
    • ...: tls.createSecureContext() 選項,如果沒有 secureContext 選項,就會使用這些選項。否則,它們會被忽略。

從現有的 TCP socket 建立新的 tls.TLSSocket 物件。

事件:'keylog'#

  • line <Buffer> NSS SSLKEYLOGFILE 格式的 ASCII 文字行。

當 socket 產生或收到金鑰材料時,tls.TLSSocket 上會發出 keylog 事件。此金鑰材料可儲存以進行偵錯,因為它允許解密擷取的 TLS 流量。它可能會在交握完成之前或之後發出多次。

典型的使用案例是將接收到的行附加到共用文字檔案,該檔案稍後會由軟體(例如 Wireshark)用來解密流量

const logFile = fs.createWriteStream('/tmp/ssl-keys.log', { flags: 'a' });
// ...
tlsSocket.on('keylog', (line) => logFile.write(line)); 

事件:'OCSPResponse'#

如果在建立 tls.TLSSocket 時設定了 requestOCSP 選項,且已收到 OCSP 回應,則會發出 'OCSPResponse' 事件。呼叫時,會將單一引數傳遞給監聽器回呼函式

  • response <Buffer> 伺服器的 OCSP 回應

通常,response 是來自伺服器 CA 的數位簽章物件,其中包含有關伺服器憑證吊銷狀態的資訊。

事件:'secureConnect'#

在成功完成新連線的交握程序後,會發出 'secureConnect' 事件。無論伺服器的憑證是否已授權,都會呼叫監聽器回呼函式。由用戶端負責檢查 tlsSocket.authorized 屬性,以確定伺服器憑證是否由指定的 CA 之一簽署。如果 tlsSocket.authorized === false,則可透過檢查 tlsSocket.authorizationError 屬性來找出錯誤。如果使用了 ALPN,則可以檢查 tlsSocket.alpnProtocol 屬性來確定協商的通訊協定。

當使用 new tls.TLSSocket() 建構函式建立 <tls.TLSSocket> 時,不會發出 'secureConnect' 事件。

事件:'session'#

當新的會話或 TLS 驗證碼可用時,會在用戶端 tls.TLSSocket 上發出 'session' 事件。這可能在交握完成之前,也可能在交握完成之後,這取決於協商的 TLS 協定版本。如果未建立新的會話(例如,當連線已恢復時),則不會在伺服器上發出事件。對於某些 TLS 協定版本,可能會多次發出事件,在這種情況下,所有會話都可以用於恢復。

在用戶端,session 可以提供給 tls.connect()session 選項,以恢復連線。

有關更多資訊,請參閱 會話續接

對於 TLSv1.2 及以下版本,可以在交握完成後呼叫 tls.TLSSocket.getSession()。對於 TLSv1.3,協定只允許基於驗證碼的恢復,會傳送多個驗證碼,而且驗證碼直到交握完成後才會傳送。因此,有必要等待 'session' 事件才能取得可恢復的會話。應用程式應使用 'session' 事件,而不是 getSession(),以確保它們適用於所有 TLS 版本。只預期取得或使用一個會話的應用程式應只聆聽此事件一次

tlsSocket.once('session', (session) => {
  // The session can be used immediately or later.
  tls.connect({
    session: session,
    // Other connect options...
  });
}); 

tlsSocket.address()#

傳回底層 socket 的繫結 address、地址 family 名稱和 port,根據作業系統報告:{ port: 12346, family: 'IPv4', address: '127.0.0.1' }

tlsSocket.authorizationError#

傳回對方的憑證未驗證的原因。此屬性僅在 tlsSocket.authorized === false 時設定。

tlsSocket.authorized#

如果對方的憑證是由建立 tls.TLSSocket 執行個體時指定的其中一個 CA 簽署,此屬性為 true;否則為 false

tlsSocket.disableRenegotiation()#

停用此 TLSSocket 執行個體的 TLS 重新協商。呼叫後,嘗試重新協商會在 TLSSocket 上觸發 'error' 事件。

tlsSocket.enableTrace()#

啟用後,TLS 封包追蹤資訊會寫入 stderr。這可以用於除錯 TLS 連線問題。

輸出的格式與 openssl s_client -traceopenssl s_server -trace 的輸出相同。雖然它是由 OpenSSL 的 SSL_trace() 函式產生,但格式未記錄,可能會不經通知而變更,且不應依賴它。

tlsSocket.encrypted#

總是傳回 true。這可以用來區分 TLS socket 和一般 net.Socket 實例。

tlsSocket.exportKeyingMaterial(length, label[, context])#

金鑰材料用於驗證以防止網路通訊協定中不同類型的攻擊,例如 IEEE 802.1X 的規範中。

範例

const keyingMaterial = tlsSocket.exportKeyingMaterial(
  128,
  'client finished');

/*
 Example return value of keyingMaterial:
 <Buffer 76 26 af 99 c5 56 8e 42 09 91 ef 9f 93 cb ad 6c 7b 65 f8 53 f1 d8 d9
    12 5a 33 b8 b5 25 df 7b 37 9f e0 e2 4f b8 67 83 a3 2f cd 5d 41 42 4c 91
    74 ef 2c ... 78 more bytes>
*/ 

請參閱 OpenSSL SSL_export_keying_material 文件以取得更多資訊。

tlsSocket.getCertificate()#

傳回表示本機憑證的物件。傳回的物件有一些屬性對應於憑證的欄位。

請參閱 tls.TLSSocket.getPeerCertificate() 以取得憑證結構的範例。

如果沒有本機憑證,將會傳回一個空物件。如果 socket 已被銷毀,將會傳回 null

tlsSocket.getCipher()#

傳回包含已協商加密組資訊的物件。

例如,具有 AES256-SHA 加密器的 TLSv1.2 協定

{
    "name": "AES256-SHA",
    "standardName": "TLS_RSA_WITH_AES_256_CBC_SHA",
    "version": "SSLv3"
} 

有關更多資訊,請參閱 SSL_CIPHER_get_name

tlsSocket.getEphemeralKeyInfo()#

傳回一個物件,表示在客戶端連線上的 完美向前保密 中,臨時金鑰交換的類型、名稱和參數大小。如果金鑰交換不是臨時的,則會傳回一個空物件。由於這僅支援於客戶端 socket;如果在伺服器 socket 上呼叫,則會傳回 null。支援的類型為 'DH''ECDH'。僅當類型為 'ECDH' 時,name 屬性才可用。

例如:{ type: 'ECDH', name: 'prime256v1', size: 256 }

tlsSocket.getFinished()#

  • 傳回:<Buffer> | <未定義> 最新 Finished 訊息,已作為 SSL/TLS 交握的一部分傳送至 socket,或 undefined(如果尚未傳送 Finished 訊息)。

由於Finished 訊息是完整握手訊息摘要(TLS 1.0 總共 192 位元,SSL 3.0 則更多),當 SSL/TLS 提供的驗證不理想或不足時,可將其用於外部驗證程序。

對應於 OpenSSL 中的 SSL_get_finished 常式,可用於實作 RFC 5929 中的 tls-unique 通道繫結。

tlsSocket.getPeerCertificate([detailed])#

  • detailed <布林值> 如果為 true,則包含完整的憑證鏈,否則僅包含同儕的憑證。
  • 傳回:<物件> 憑證物件。

傳回表示同儕憑證的物件。如果同儕未提供憑證,則會傳回一個空的物件。如果 socket 已毀損,則會傳回 null

如果要求提供完整的憑證鏈,則每張憑證都會包含一個 issuerCertificate 屬性,其中包含一個表示其發行者憑證的物件。

憑證物件#

憑證物件的屬性對應於憑證的欄位。

  • ca <布林值> 如果是憑證授權 (CA),則為 true,否則為 false
  • raw <Buffer> DER 編碼的 X.509 憑證資料。
  • subject <物件> 憑證主旨,以國家 (C)、州或省 (ST)、地區 (L)、組織 (O)、組織單位 (OU) 和主體名稱 (CN) 說明。主體名稱通常是 TLS 憑證的 DNS 名稱。範例:{C: 'UK', ST: 'BC', L: 'Metro', O: 'Node Fans', OU: 'Docs', CN: 'example.com'}
  • issuer <物件> 憑證發行者,說明方式與 subject 相同。
  • valid_from <字串> 憑證有效的起迄時間。
  • valid_to <字串> 憑證有效的迄止時間。
  • serialNumber <字串> 憑證序號,為一十六進位字串。範例:'B9B0D332A1AA5635'
  • fingerprint <字串> DER 編碼憑證的 SHA-1 摘要。以 : 分隔的十六進位字串形式傳回。範例:'2A:7A:C2:DD:...'
  • fingerprint256 <字串> DER 編碼憑證的 SHA-256 摘要。以 : 分隔的十六進位字串形式傳回。範例:'2A:7A:C2:DD:...'
  • fingerprint512 <字串> DER 編碼憑證的 SHA-512 摘要。以 : 分隔的十六進位字串形式傳回。範例:'2A:7A:C2:DD:...'
  • ext_key_usage <陣列>(選用)擴充金鑰用途,一組 OID。
  • subjectaltname <字串>(選用)包含主體串接名稱的字串,作為 subject 名稱的替代方案。
  • infoAccess <陣列>(選用)描述 AuthorityInfoAccess 的陣列,與 OCSP 搭配使用。
  • issuerCertificate <物件>(選用)發行者憑證物件。對於自簽憑證,這可能會形成循環參照。

憑證可能會包含公開金鑰的資訊,依據金鑰類型而定。

對於 RSA 金鑰,可能會定義下列屬性

  • bits <number> RSA 位元大小。範例:1024
  • exponent <string> RSA 指數,為十六進位數字表示的字串。範例:'0x010001'
  • modulus <string> RSA 模數,為十六進位字串。範例:'B56CE45CB7...'
  • pubkey <Buffer> 公開金鑰。

對於 EC 金鑰,可能會定義下列屬性

  • pubkey <Buffer> 公開金鑰。
  • bits <number> 金鑰大小(以位元為單位)。範例:256
  • asn1Curve <string>(選用)橢圓曲線 OID 的 ASN.1 名稱。已知的曲線會以 OID 識別。雖然不常見,但曲線有可能以其數學屬性識別,這種情況下它不會有 OID。範例:'prime256v1'
  • nistCurve <string>(選用)橢圓曲線的 NIST 名稱(如果有的話,並非所有已知的曲線都已由 NIST 分配名稱)。範例:'P-256'

範例憑證

{ subject:
   { OU: [ 'Domain Control Validated', 'PositiveSSL Wildcard' ],
     CN: '*.nodejs.org' },
  issuer:
   { C: 'GB',
     ST: 'Greater Manchester',
     L: 'Salford',
     O: 'COMODO CA Limited',
     CN: 'COMODO RSA Domain Validation Secure Server CA' },
  subjectaltname: 'DNS:*.nodejs.org, DNS:nodejs.org',
  infoAccess:
   { 'CA Issuers - URI':
      [ 'http://crt.comodoca.com/COMODORSADomainValidationSecureServerCA.crt' ],
     'OCSP - URI': [ 'http://ocsp.comodoca.com' ] },
  modulus: 'B56CE45CB740B09A13F64AC543B712FF9EE8E4C284B542A1708A27E82A8D151CA178153E12E6DDA15BF70FFD96CB8A88618641BDFCCA03527E665B70D779C8A349A6F88FD4EF6557180BD4C98192872BCFE3AF56E863C09DDD8BC1EC58DF9D94F914F0369102B2870BECFA1348A0838C9C49BD1C20124B442477572347047506B1FCD658A80D0C44BCC16BC5C5496CFE6E4A8428EF654CD3D8972BF6E5BFAD59C93006830B5EB1056BBB38B53D1464FA6E02BFDF2FF66CD949486F0775EC43034EC2602AEFBF1703AD221DAA2A88353C3B6A688EFE8387811F645CEED7B3FE46E1F8B9F59FAD028F349B9BC14211D5830994D055EEA3D547911E07A0ADDEB8A82B9188E58720D95CD478EEC9AF1F17BE8141BE80906F1A339445A7EB5B285F68039B0F294598A7D1C0005FC22B5271B0752F58CCDEF8C8FD856FB7AE21C80B8A2CE983AE94046E53EDE4CB89F42502D31B5360771C01C80155918637490550E3F555E2EE75CC8C636DDE3633CFEDD62E91BF0F7688273694EEEBA20C2FC9F14A2A435517BC1D7373922463409AB603295CEB0BB53787A334C9CA3CA8B30005C5A62FC0715083462E00719A8FA3ED0A9828C3871360A73F8B04A4FC1E71302844E9BB9940B77E745C9D91F226D71AFCAD4B113AAF68D92B24DDB4A2136B55A1CD1ADF39605B63CB639038ED0F4C987689866743A68769CC55847E4A06D6E2E3F1',
  exponent: '0x10001',
  pubkey: <Buffer ... >,
  valid_from: 'Aug 14 00:00:00 2017 GMT',
  valid_to: 'Nov 20 23:59:59 2019 GMT',
  fingerprint: '01:02:59:D9:C3:D2:0D:08:F7:82:4E:44:A4:B4:53:C5:E2:3A:87:4D',
  fingerprint256: '69:AE:1A:6A:D4:3D:C6:C1:1B:EA:C6:23:DE:BA:2A:14:62:62:93:5C:7A:EA:06:41:9B:0B:BC:87:CE:48:4E:02',
  fingerprint512: '19:2B:3E:C3:B3:5B:32:E8:AE:BB:78:97:27:E4:BA:6C:39:C9:92:79:4F:31:46:39:E2:70:E5:5F:89:42:17:C9:E8:64:CA:FF:BB:72:56:73:6E:28:8A:92:7E:A3:2A:15:8B:C2:E0:45:CA:C3:BC:EA:40:52:EC:CA:A2:68:CB:32',
  ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ],
  serialNumber: '66593D57F20CBC573E433381B5FEC280',
  raw: <Buffer ... > } 

tlsSocket.getPeerFinished()#

  • 傳回:<Buffer> | <undefined> 預期或實際從 socket 收到的最新 Finished 訊息,作為 SSL/TLS 交握的一部分,或者如果目前沒有 Finished 訊息,則傳回 undefined

由於Finished 訊息是完整握手訊息摘要(TLS 1.0 總共 192 位元,SSL 3.0 則更多),當 SSL/TLS 提供的驗證不理想或不足時,可將其用於外部驗證程序。

對應到 OpenSSL 中的 SSL_get_peer_finished 常式,可用來實作 RFC 5929 中的 tls-unique 通道繫結。

tlsSocket.getPeerX509Certificate()#

傳回對等憑證,為 <X509Certificate> 物件。

如果沒有對等憑證,或 socket 已被銷毀,將傳回 undefined

tlsSocket.getProtocol()#

傳回包含目前連線協商的 SSL/TLS 協定版本字串。尚未完成握手程序的已連線 socket 將傳回值 'unknown'。伺服器 socket 或已中斷連線的用戶端 socket 將傳回值 null

協定版本為

  • 'SSLv3'
  • 'TLSv1'
  • 'TLSv1.1'
  • 'TLSv1.2'
  • 'TLSv1.3'

請參閱 OpenSSL SSL_get_version 文件,以取得更多資訊。

tlsSocket.getSession()#

傳回 TLS 會話資料,或在未協商會話時傳回 undefined。在用戶端,資料可提供給 tls.connect()session 選項,以重新連線。在伺服器上,這可能有助於除錯。

有關更多資訊,請參閱 會話續接

注意:getSession() 僅適用於 TLSv1.2 及以下版本。對於 TLSv1.3,應用程式必須使用 'session' 事件(它也適用於 TLSv1.2 及以下版本)。

tlsSocket.getSharedSigalgs()#

  • 傳回:<Array> 伺服器與用戶端之間共用的簽章演算法清單,依偏好順序遞減排列。

請參閱 SSL_get_shared_sigalgs 以取得更多資訊。

tlsSocket.getTLSTicket()#

對於用戶端,傳回 TLS 會話票證(如果有的話),否則傳回 undefined。對於伺服器,總是傳回 undefined

這可能有助於除錯。

有關更多資訊,請參閱 會話續接

tlsSocket.getX509Certificate()#

傳回本機憑證,為 <X509Certificate> 物件。

如果沒有本機憑證,或 socket 已被銷毀,將傳回 undefined

tlsSocket.isSessionReused()#

  • 傳回:<boolean> 如果會話已重複使用,則為 true,否則為 false

有關更多資訊,請參閱 會話續接

tlsSocket.localAddress#

傳回本機 IP 位址的字串表示形式。

tlsSocket.localPort#

傳回本機埠號的數字表示形式。

tlsSocket.remoteAddress#

傳回遠端 IP 位址的字串表示。例如,'74.125.127.100''2001:4860:a005::68'

tlsSocket.remoteFamily#

傳回遠端 IP 家族的字串表示。'IPv4''IPv6'

tlsSocket.remotePort#

傳回遠端埠號的數字表示。例如,443

tlsSocket.renegotiate(options, callback)#

  • options <Object>

    • rejectUnauthorized <boolean> 如果不是 false,伺服器憑證會針對提供的 CA 清單進行驗證。如果驗證失敗,則會發出 'error' 事件;err.code 包含 OpenSSL 錯誤碼。預設值:true
    • requestCert
  • callback <Function> 如果 renegotiate() 傳回 true,則會將回呼附加一次到 'secure' 事件。如果 renegotiate() 傳回 false,則會在下一刻呼叫 callback,並附帶一個錯誤,除非 tlsSocket 已被銷毀,否則根本不會呼叫 callback

  • 傳回:<boolean> 如果已啟動重新協商,則為 true,否則為 false

tlsSocket.renegotiate() 方法會啟動 TLS 重新協商程序。完成後,callback 函式會傳遞一個單一參數,可能是 Error(如果要求失敗)或 null

此方法可用於在建立安全連線後請求對方的憑證。

作為伺服器執行時,在 `handshakeTimeout` 超時後,套接字會因錯誤而中斷。

對於 TLSv1.3,無法啟動重新協商,此協定不支援此功能。

tlsSocket.setMaxSendFragment(size)#

  • size <number> 最大 TLS 片段大小。最大值為 `16384`。預設值:16384
  • 傳回:<boolean>

tlsSocket.setMaxSendFragment() 方法設定最大 TLS 片段大小。如果設定限制成功,則傳回 `true`;否則傳回 `false`。

較小的片段大小會減少用戶端上的緩衝延遲:較大的片段會由 TLS 層緩衝,直到收到整個片段並驗證其完整性為止;大型片段可能會跨越多個回合行程,而且其處理可能會因封包遺失或重新排序而延遲。但是,較小的片段會增加額外的 TLS 框架位元組和 CPU 負載,這可能會降低整體伺服器吞吐量。

tls.checkServerIdentity(hostname, cert)#

驗證憑證 `cert` 是否已核發給 `hostname`。

傳回 <Error> 物件,在失敗時會以 reasonhostcert 填入。在成功時,傳回 <undefined>

此函式旨在與可傳遞至 tls.connect()checkServerIdentity 選項結合使用,並因此在 憑證物件 上執行。對於其他用途,請考慮改用 x509.checkHost()

此函式可透過提供替代函式作為傳遞至 tls.connect()options.checkServerIdentity 選項來覆寫。覆寫函式當然可以呼叫 tls.checkServerIdentity(),以透過其他驗證來擴充所執行的檢查。

此函式僅在憑證通過所有其他檢查(例如由受信任的 CA 頒發(options.ca))時才會呼叫。

較早版本的 Node.js 會錯誤地接受給定 hostname 的憑證,如果存在相符的 uniformResourceIdentifier 主體備用名稱(請參閱 CVE-2021-44531)。希望接受 uniformResourceIdentifier 主體備用名稱的應用程式可以使用自訂 options.checkServerIdentity 函式,來實作所需的行為。

tls.connect(options[, callback])#

  • options <Object>
    • enableTrace:請參閱 tls.createServer()

    • host <string> 應該連接的客戶端主機。預設值:'localhost'

    • port <number> 應該連接的客戶端埠。

    • path <string> 建立到路徑的 Unix socket 連線。如果指定此選項,則會忽略 hostport

    • socket <stream.Duplex> 在既有的 socket 上建立安全連線,而不是建立新的 socket。通常,這是 net.Socket 的執行個體,但允許任何 Duplex 串流。如果指定此選項,則會忽略 pathhostport,但驗證憑證除外。通常,在傳遞給 tls.connect() 時,socket 已連線,但稍後可以連線。socket 的連線/斷線/毀損是使用者的責任;呼叫 tls.connect() 不會導致呼叫 net.connect()

    • allowHalfOpen <布林值> 如果設為 false,則在可讀取端結束時,socket 將自動結束可寫入端。如果設定 socket 選項,此選項將不會生效。有關詳細資訊,請參閱 net.SocketallowHalfOpen 選項。預設:false

    • rejectUnauthorized <boolean> 如果不是 false,伺服器憑證會針對提供的 CA 清單進行驗證。如果驗證失敗,則會發出 'error' 事件;err.code 包含 OpenSSL 錯誤碼。預設值:true

    • pskCallback <函式>

      • 提示:<字串> 從伺服器傳送的選用訊息,協助用戶端在協商期間決定要使用哪個身分。如果使用 TLS 1.3,則始終為 null
      • 傳回:<物件> 格式為 { psk: <Buffer|TypedArray|DataView>, identity: <字串> } 的物件,或 null 以停止協商程序。psk 必須與所選密碼的摘要相容。identity 必須使用 UTF-8 編碼。

      在協商 TLS-PSK(預先共用金鑰)時,會呼叫此函式,並提供伺服器提供的選用身分 hint,或在移除 hint 的 TLS 1.3 中提供 null。將需要為連線提供自訂 tls.checkServerIdentity(),因為預設值會嘗試根據憑證檢查伺服器的主機名稱/IP,但這不適用於 PSK,因為不會有憑證。可以在 RFC 4279 中找到更多資訊。

    • ALPNProtocols<字串陣列> | <Buffer 陣列> | <TypedArray 陣列> | <DataView 陣列> | <Buffer> | <TypedArray> | <DataView> 一個字串、BufferTypedArrayDataView 陣列,或一個包含支援的 ALPN 協定的單一 BufferTypedArrayDataViewBuffer 應採用格式 [長度][名稱][長度][名稱]...,例如 '\x08http/1.1\x08http/1.0',其中 長度 位元組是下一個協定名稱的長度。傳遞陣列通常簡單得多,例如 ['http/1.1', 'http/1.0']。清單中較早的協定優先於較晚的協定。

    • servername<字串> SNI (伺服器名稱指示) TLS 擴充功能的伺服器名稱。這是正在連線的主機名稱,必須是主機名稱,而非 IP 位址。多宿主伺服器可以使用它來選擇要提供給客戶端的正確憑證,請參閱 SNICallback 選項至 tls.createServer()

    • checkServerIdentity(servername, cert) <函數> 檢查伺服器主機名稱(或在明確設定時提供的 servername)與憑證時,要使用的回呼函數(取代內建的 tls.checkServerIdentity() 函數)。如果驗證失敗,應傳回 <錯誤>。如果驗證 servernamecert,則方法應傳回 undefined

    • session <Buffer> 包含 TLS 會話的 Buffer 執行個體。

    • minDHSize <數字> 接受 TLS 連線時,DH 參數的最小位元大小。當伺服器提供的 DH 參數大小小於 minDHSize 時,TLS 連線會中斷,並擲回錯誤。預設值: 1024

    • highWaterMark<數字> 與可讀取串流 highWaterMark 參數一致。預設值: 16 * 1024

    • secureContext:使用 tls.createSecureContext() 建立的 TLS 內容物件。如果 沒有 提供 secureContext,將會透過將整個 options 物件傳遞給 tls.createSecureContext() 來建立一個。

    • onread <物件> 如果缺少 socket 選項,則會將接收資料儲存在單一 buffer 中,並在資料到達 socket 時傳遞給提供的 callback,否則會略過此選項。有關詳細資訊,請參閱 net.Socketonread 選項。

    • ...: tls.createSecureContext() 選項,如果缺少 secureContext 選項,則會使用這些選項,否則會略過這些選項。

    • ...: 任何尚未列出的 socket.connect() 選項。

  • callback <函數>
  • 傳回:<tls.TLSSocket>

如果指定了 callback 函數,則會將它新增為 'secureConnect' 事件的監聽器。

tls.connect() 會傳回 tls.TLSSocket 物件。

https API 不同,tls.connect() 預設不會啟用 SNI (伺服器名稱指示) 擴充功能,這可能會導致某些伺服器傳回不正確的憑證或完全拒絕連線。若要啟用 SNI,請設定 servername 選項,並加上 host

以下說明 tls.createServer() 中 echo 伺服器範例的用戶端

// Assumes an echo server that is listening on port 8000.
const tls = require('node:tls');
const fs = require('node:fs');

const options = {
  // Necessary only if the server requires client certificate authentication.
  key: fs.readFileSync('client-key.pem'),
  cert: fs.readFileSync('client-cert.pem'),

  // Necessary only if the server uses a self-signed certificate.
  ca: [ fs.readFileSync('server-cert.pem') ],

  // Necessary only if the server's cert isn't for "localhost".
  checkServerIdentity: () => { return null; },
};

const socket = tls.connect(8000, options, () => {
  console.log('client connected',
              socket.authorized ? 'authorized' : 'unauthorized');
  process.stdin.pipe(socket);
  process.stdin.resume();
});
socket.setEncoding('utf8');
socket.on('data', (data) => {
  console.log(data);
});
socket.on('end', () => {
  console.log('server ends connection');
}); 

tls.connect(path[, options][, callback])#

tls.connect() 相同,但可以將 path 提供為引數,而不是選項。

如果指定了路徑選項,則優先於路徑引數。

tls.connect(port[, host][, options][, callback])#

tls.connect() 相同,但可以將 porthost 提供為引數,而不是選項。

如果指定了 port 或 host 選項,則優先於任何 port 或 host 引數。

tls.createSecureContext([選項])#

  • options <Object>
    • ca <字串> | <字串陣列> | <Buffer> | <Buffer陣列> 選擇性覆寫受信任的 CA 憑證。預設為信任 Mozilla 策劃的知名 CA。當使用此選項明確指定 CA 時,Mozilla 的 CA 會被完全取代。此值可以是字串或 Buffer,或字串和/或 Buffer 的陣列。任何字串或 Buffer 都可以包含多個 PEM CA 串接在一起。對方的憑證必須可以鏈結到伺服器信任的 CA,才能驗證連線。當使用無法鏈結到知名 CA 的憑證時,必須明確指定憑證的 CA 為受信任的,否則連線將無法驗證。如果對方使用與預設 CA 不匹配或無法鏈結到預設 CA 的憑證,請使用 ca 選項提供對方的憑證可以匹配或鏈結到的 CA 憑證。對於自簽憑證,憑證是其自己的 CA,且必須提供。對於 PEM 編碼的憑證,支援的類型為「受信任憑證」、「X509 憑證」和「憑證」。另請參閱 tls.rootCertificates
    • cert <字串> | <字串陣列> | <Buffer> | <Buffer陣列> PEM 格式的憑證鏈。應為每個私密金鑰提供一個憑證鏈。每個憑證鏈應包含已提供的私密 金鑰 的 PEM 格式憑證,接著是 PEM 格式的中階憑證(如果有),依序排列,且不包括根 CA(根 CA 必須是對等方預先知道的,請參閱 ca)。提供多個憑證鏈時,它們不必與 金鑰 中的私密金鑰順序相同。如果未提供中階憑證,對等方將無法驗證憑證,且交握將會失敗。
    • sigalgs <字串> 以冒號分隔的支援簽章演算法清單。清單中可以包含摘要演算法(SHA256MD5 等)、公開金鑰演算法(RSA-PSSECDSA 等)、兩者的組合(例如「RSA+SHA384」)或 TLS v1.3 架構名稱(例如 rsa_pss_pss_sha512)。請參閱 OpenSSL 手冊頁面 以取得更多資訊。
    • ciphers <字串> 取代預設值的密碼組規格。如需更多資訊,請參閱 修改預設 TLS 密碼組。可透過 tls.getCiphers() 取得允許的密碼。密碼名稱必須使用大寫,OpenSSL 才能接受。
    • clientCertEngine <字串> 可提供用戶端憑證的 OpenSSL 引擎名稱。
    • crl <字串> | <字串陣列> | <Buffer> | <Buffer 陣列> PEM 格式的 CRL(憑證撤銷清單)。
    • dhparam <字串> | <Buffer> 'auto' 或自訂 Diffie-Hellman 參數,非 ECDHE 完美前向安全性 所需。如果省略或無效,參數將會靜默捨棄,而且 DHE 密碼將不可用。基於 ECDHE完美前向安全性 仍會可用。
    • ecdhCurve <字串> 描述已命名曲線或以冒號分隔的曲線 NID 或名稱清單的字串,例如 P-521:P-384:P-256,用於 ECDH 金鑰協商。設為 auto 以自動選取曲線。使用 crypto.getCurves() 取得可用曲線名稱清單。在最近的版本中,openssl ecparam -list_curves 也會顯示每個可用橢圓曲線的名稱和說明。預設值: tls.DEFAULT_ECDH_CURVE
    • honorCipherOrder <boolean> 嘗試使用伺服器的密碼套件偏好設定,而不是客戶端的偏好設定。當 true 時,會在 secureOptions 中設定 SSL_OP_CIPHER_SERVER_PREFERENCE,有關更多資訊,請參閱 OpenSSL 選項
    • key <string> | <string[]> | <Buffer> | <Buffer[]> | <Object[]> PEM 格式的私人金鑰。PEM 允許加密私人金鑰。加密的金鑰會使用 options.passphrase 解密。可以使用未加密的金鑰字串或緩衝區陣列,或以 {pem: <string|buffer>[, passphrase: <string>]} 形式的物件陣列提供使用不同演算法的多個金鑰。物件形式只能出現在陣列中。object.passphrase 是選用的。如果提供 object.passphrase,則會使用它解密加密的金鑰,否則會使用 options.passphrase
    • privateKeyEngine <string> 取得私人金鑰的 OpenSSL 引擎名稱。應與 privateKeyIdentifier 一起使用。
    • privateKeyIdentifier <string> 由 OpenSSL 引擎管理的私人金鑰識別碼。應與 privateKeyEngine 一起使用。不應與 key 一起設定,因為這兩個選項以不同的方式定義私人金鑰。
    • maxVersion <字串> 選擇性設定允許的最大 TLS 版本。其中之一:'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1'。無法與 secureProtocol 選項一起指定;請使用其中一個。預設: tls.DEFAULT_MAX_VERSION
    • minVersion <字串> 選擇性設定允許的最小 TLS 版本。其中之一:'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1'。無法與 secureProtocol 選項一起指定;請使用其中一個。避免設定為低於 TLSv1.2,但可能需要這樣做才能相容。預設: tls.DEFAULT_MIN_VERSION
    • passphrase <字串> 用於單一私密金鑰和/或 PFX 的共用通行碼。
    • pfx <字串> | <字串[]> | <Buffer> | <Buffer[]> | <物件[]> PFX 或 PKCS12 編碼的私密金鑰和憑證鏈。pfx 是個別提供 keycert 的替代方案。PFX 通常會加密,如果是的話,passphrase 會用來解密。可以提供多個 PFX,作為未加密 PFX 緩衝區陣列,或以 {buf: <字串|緩衝區>[, passphrase: <字串>]} 形式的物件陣列。物件形式只能出現在陣列中。object.passphrase 是選用的。如果提供 object.passphrase,會用它來解密已加密的 PFX;如果沒有提供,則會使用 options.passphrase
    • secureOptions <數字> 選擇性影響 OpenSSL 協定行為,通常不需要這樣做。如果需要,應小心使用!值是 OpenSSL 選項SSL_OP_* 選項的數字位元遮罩。
    • secureProtocol <字串> 選擇要使用的 TLS 協定的舊版機制,它不支援獨立控制最小和最大版本,也不支援將協定限制為 TLSv1.3。請改用 minVersionmaxVersion。可能的數值列在 SSL_METHODS 中,請使用函式名稱作為字串。例如,使用 'TLSv1_1_method' 來強制使用 TLS 版本 1.1,或使用 'TLS_method' 來允許任何 TLS 協定版本(最高到 TLSv1.3)。不建議使用低於 1.2 的 TLS 版本,但可能需要這樣做才能進行互操作。預設值:無,請參閱 minVersion
    • sessionIdContext <字串> 伺服器使用的不透明識別碼,用來確保應用程式之間不會共用會話狀態。用戶端不用。
    • ticketKeys: <Buffer> 48 位元組的密碼學上強的偽亂數資料。請參閱 會話復原 以取得更多資訊。
    • sessionTimeout <數字> 伺服器建立的 TLS 會話在多少秒後將不再可復原。請參閱 會話復原 以取得更多資訊。預設值:300

tls.createServer()honorCipherOrder 選項的預設值設為 true,建立安全內容的其他 API 則會將其設為未設定。

tls.createServer() 使用從 process.argv 產生的 128 位元截斷 SHA1 雜湊值作為 sessionIdContext 選項的預設值,建立安全內容的其他 API 沒有預設值。

tls.createSecureContext() 方法會建立一個 SecureContext 物件。它可用作數個 tls API 的引數,例如 server.addContext(),但沒有公開方法。tls.Server 建構函式和 tls.createServer() 方法不支援 secureContext 選項。

使用憑證的密碼需要一個金鑰。可以使用 keypfx 來提供金鑰。

如果沒有提供 ca 選項,Node.js 會預設使用 Mozilla 的公開信任 CA 清單

建議使用新的 dhparam: 'auto' 選項,而非自訂 DHE 參數。將其設定為 'auto' 時,將自動選取強度足夠的已知 DHE 參數。否則,如有需要,可以使用 openssl dhparam 來建立自訂參數。金鑰長度必須大於或等於 1024 位元,否則會擲回錯誤。雖然 1024 位元是允許的,但建議使用 2048 位元或更大的長度以增強安全性。

tls.createSecurePair([context][, isServer][, requestCert][, rejectUnauthorized][, options])#

穩定性:0 - 已棄用:請改用 tls.TLSSocket

  • context <Object>tls.createSecureContext() 回傳的安全內容物件
  • isServer <boolean> true 表示此 TLS 連線應以伺服器身分開啟。
  • requestCert <boolean> true 表示伺服器是否應向連線中的用戶端要求憑證。僅在 isServertrue 時適用。
  • rejectUnauthorized <boolean> 若非 false,伺服器會自動拒絕憑證無效的用戶端。僅在 isServertrue 時適用。
  • 選項

建立一個新的安全配對物件,其中包含兩個串流,一個用於讀取和寫入加密資料,另一個用於讀取和寫入明文資料。通常,加密串流會導向/導出至一個輸入的加密資料串流,而明文串流則用來取代最初的加密串流。

tls.createSecurePair() 會傳回一個 tls.SecurePair 物件,其中包含 cleartextencrypted 串流屬性。

使用 cleartext 的 API 與 tls.TLSSocket 相同。

tls.createSecurePair() 方法現已棄用,建議改用 tls.TLSSocket()。例如,下列程式碼

pair = tls.createSecurePair(/* ... */);
pair.encrypted.pipe(socket);
socket.pipe(pair.encrypted); 

可以替換為

secureSocket = tls.TLSSocket(socket, options); 

其中 secureSocket 的 API 與 pair.cleartext 相同。

tls.createServer([options][, secureConnectionListener])#

  • options <Object>
    • ALPNProtocols: <字串陣列> | <Buffer 陣列> | <TypedArray 陣列> | <DataView 陣列> | <Buffer> | <TypedArray> | <DataView> 一個字串、BufferTypedArrayDataView 陣列,或一個包含支援 ALPN 通訊協定的 BufferTypedArrayDataViewBuffer 應採用 [len][name][len][name]... 格式,例如 0x05hello0x05world,其中第一個位元組為下一個通訊協定名稱的長度。傳遞陣列通常簡單許多,例如 ['hello', 'world']。(通訊協定應依其優先順序排序。)

    • ALPNCallback<函式>如果設定,當客戶端使用 ALPN 擴充功能開啟連線時,將呼叫此函式。會將一個參數傳遞給回呼:一個包含 servernameprotocols 欄位的物件,分別包含來自 SNI 擴充功能的伺服器名稱(如果有的話)和 ALPN 協定名稱字串的陣列。回呼必須傳回 protocols 中列出的字串之一,該字串將傳回給客戶端作為選取的 ALPN 協定,或 undefined,以使用致命警示拒絕連線。如果傳回的字串與客戶端的 ALPN 協定之一不符,將擲回錯誤。此選項無法與 ALPNProtocols 選項搭配使用,且設定兩個選項將擲回錯誤。

    • clientCertEngine <字串> 可提供用戶端憑證的 OpenSSL 引擎名稱。

    • enableTrace <布林值>如果為 true,將在新的連線上呼叫 tls.TLSSocket.enableTrace()。可以在建立安全連線後啟用追蹤,但此選項必須用於追蹤安全連線設定。預設: false

    • handshakeTimeout <數字>如果 SSL/TLS 交握未在指定的毫秒數內完成,則中止連線。每當交握逾時,就會在 tls.Server 物件上發出 'tlsClientError'預設: 120000(120 秒)。

    • rejectUnauthorized <布林值>如果非 false,伺服器將拒絕任何未經提供的 CA 清單授權的連線。此選項僅在 requestCerttrue 時有效。預設: true

    • requestCert <布林值> 如果為 true,伺服器將要求連線的用戶端提供憑證,並嘗試驗證該憑證。預設值:false

    • sessionTimeout <數字> 伺服器建立的 TLS 會話在多少秒後將不再可復原。請參閱 會話復原 以取得更多資訊。預設值:300

    • SNICallback(伺服器名稱, 回呼函式) <函式> 如果用戶端支援 SNI TLS 擴充功能,將呼叫此函式。呼叫時會傳遞兩個參數:伺服器名稱回呼函式回呼函式 是錯誤優先回呼函式,它需要兩個選用參數:錯誤ctx。如果提供 ctx,它會是 SecureContext 實例。可以使用 tls.createSecureContext() 來取得適當的 SecureContext。如果 回呼函式 以假值 ctx 參數呼叫,將會使用伺服器的預設安全內容。如果未提供 SNICallback,將會使用具有高階 API 的預設回呼函式(詳見下方)。

    • ticketKeys: <Buffer> 48 位元組的密碼學上強的偽亂數資料。請參閱 會話復原 以取得更多資訊。

    • pskCallback <函式>

      在協商 TLS-PSK(預先共享金鑰)時,這個函式會呼叫提供給客戶端的識別碼。如果傳回值為 null,協商程序將會停止,並會傳送「unknown_psk_identity」警示訊息給另一方。如果伺服器希望隱藏 PSK 識別碼不為人知的這個事實,回呼必須提供一些隨機資料作為 psk,讓連線在協商完成之前就因「decrypt_error」而失敗。PSK 加密預設為停用,因此使用 TLS-PSK 需要明確使用 ciphers 選項指定加密組。更多資訊請參閱 RFC 4279

    • pskIdentityHint <string> 選擇性的提示,在 TLS-PSK 協商期間傳送給客戶端,以協助選擇識別碼。TLS 1.3 中將會忽略。如果無法設定 pskIdentityHint,將會發出 'tlsClientError',其代碼為 'ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED'

    • ...: 可以提供任何 tls.createSecureContext() 選項。對於伺服器來說,通常需要識別碼選項(pfxkey/certpskCallback)。

    • ...: 可以提供任何 net.createServer() 選項。

  • secureConnectionListener <Function>
  • 傳回:<tls.Server>

建立新的 tls.Server。如果提供 secureConnectionListener,則會自動設定為 'secureConnection' 事件的監聽器。

ticketKeys 選項會在 node:cluster 模組工作人員之間自動共用。

以下是簡單迴音伺服器的說明

const tls = require('node:tls');
const fs = require('node:fs');

const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),

  // This is necessary only if using client certificate authentication.
  requestCert: true,

  // This is necessary only if the client uses a self-signed certificate.
  ca: [ fs.readFileSync('client-cert.pem') ],
};

const server = tls.createServer(options, (socket) => {
  console.log('server connected',
              socket.authorized ? 'authorized' : 'unauthorized');
  socket.write('welcome!\n');
  socket.setEncoding('utf8');
  socket.pipe(socket);
});
server.listen(8000, () => {
  console.log('server bound');
}); 

可以透過使用 tls.connect() 中的範例用戶端連線至伺服器來測試伺服器。

tls.getCiphers()#

傳回包含支援的 TLS 加密演算法名稱的陣列。基於歷史原因,名稱使用小寫字母,但必須使用大寫字母才能在 tls.createSecureContext()ciphers 選項中使用。

並非所有支援的加密演算法都預設啟用。請參閱 修改預設 TLS 加密演算法組

'tls_' 開頭的加密演算法名稱適用於 TLSv1.3,其他所有名稱適用於 TLSv1.2 及以下版本。

console.log(tls.getCiphers()); // ['aes128-gcm-sha256', 'aes128-sha', ...] 

tls.rootCertificates#

不可變的字串陣列,代表目前 Node.js 版本提供的已綑綁 Mozilla CA 儲存庫(PEM 格式)中的根憑證。

Node.js 提供的已綑綁 CA 儲存庫是 Mozilla CA 儲存庫的快照,在發行時固定。在所有支援的平台上都是相同的。

tls.DEFAULT_ECDH_CURVE#

在 TLS 伺服器中用於 ECDH 金鑰協定的預設曲線名稱。預設值為 'auto'。如需更多資訊,請參閱 tls.createSecureContext()

tls.DEFAULT_MAX_VERSION#

  • <string> tls.createSecureContext()maxVersion 選項的預設值。它可以指定任何受支援的 TLS 協定版本,例如 'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1'預設值:'TLSv1.3',除非使用 CLI 選項變更。使用 --tls-max-v1.2 會將預設值設為 'TLSv1.2'。使用 --tls-max-v1.3 會將預設值設為 'TLSv1.3'。如果提供多個選項,則會使用最大的最大值。

tls.DEFAULT_MIN_VERSION#

  • <string> tls.createSecureContext()minVersion 選項的預設值。它可以指定任何受支援的 TLS 協定版本,例如 'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1'預設值:'TLSv1.2',除非使用 CLI 選項變更。使用 --tls-min-v1.0 會將預設值設為 'TLSv1'。使用 --tls-min-v1.1 會將預設值設為 'TLSv1.1'。使用 --tls-min-v1.3 會將預設值設為 'TLSv1.3'。如果提供多個選項,則會使用最小的最小值。

tls.DEFAULT_CIPHERS#

  • <string> tls.createSecureContext()ciphers 選項的預設值。它可以指定任何受支援的 OpenSSL 加密。預設為 crypto.constants.defaultCoreCipherList 的內容,除非使用 --tls-default-ciphers 的 CLI 選項變更。