怎么在NodeJS中實現(xiàn)Https HSM雙向認(rèn)證?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
成都創(chuàng)新互聯(lián)公司是一家專業(yè)提供軹城企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、網(wǎng)站制作、H5網(wǎng)站設(shè)計、小程序制作等業(yè)務(wù)。10年已為軹城眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。NodeJS可以利用openSSL的HSM plugin方式實現(xiàn),但是需要編譯C++,太麻煩,作者采用了利用Node Socket接口,純JS自行實現(xiàn)Https/Http協(xié)議的方式實現(xiàn)
具體實現(xiàn)可以參考如下 node-https-hsm
TLS規(guī)范自然是參考RFC文檔 The Transport Layer Security (TLS) Protocol Version 1.2
概述
本次TLS雙向認(rèn)證支持以下加密套件(*為建議使用套件):
TLS_RSA_WITH_AES_128_CBC_SHA256(TLS v1.2) *
TLS_RSA_WITH_AES_256_CBC_SHA256(TLS v1.2) *
TLS_RSA_WITH_AES_128_CBC_SHA(TLS v1.1)
TLS_RSA_WITH_AES_256_CBC_SHA(TLS v1.1)
四種加密套件流程完全一致,只是部分算法細(xì)節(jié)與報文略有差異,體現(xiàn)在
AES_128/AES_256的會話AES密鑰長度分別為16/32字節(jié)。
TLS 1.1 在計算finish報文數(shù)據(jù)時,進(jìn)行的是MD5 + SHA1的HASH算法,而在TLS v1.2下,HASH算法變成了單次SHA256。
TLS 1.1 處理finish報文時的偽隨機(jī)算法(PRF)需要將種子數(shù)據(jù)為分兩塊,分別用 MD5 / SHA1 取HASH后異或,TLS 1.2 為單次 SHA256。
TLS 1.2 的 CertificateVerify / ServerKeyExchange 報文末尾新增2個字節(jié)的 Signature Hash Algorithm,表示 hash_alg 和 sign_alg。
目前業(yè)界推薦使用TLS v1.2, TLS v1.1不建議使用。
流程圖
以下為 TLS 完整握手流程圖
* =======================FULL HANDSHAKE====================== * Client Server * * ClientHello --------> * ServerHello * Certificate * CertificateRequest * <-------- ServerHelloDone * Certificate * ClientKeyExchange * CertificateVerify * Finished --------> * change_cipher_spec * <-------- Finished * Application Data <-------> Application Data
流程詳解
客戶端發(fā)起握手請求
TLS握手始于客戶端發(fā)起 ClientHello 請求。
struct { uint32 gmt_unix_time; // UNIX 32-bit format, UTC時間 opaque random_bytes[28]; // 28位長度隨機(jī)數(shù) } Random; //隨機(jī)數(shù) struct { ProtocolVersion client_version; // 支持的最高版本的TLS版本 Random random; // 上述隨機(jī)數(shù) SessionID session_id; // 會話ID,新會話為空 CipherSuite cipher_suites<2..2^16-2>; // 客戶端支持的所有加密套件,上述四種 CompressionMethod compression_methods<1..2^8-1>; // 壓縮算法 select (extensions_present) { // 額外插件,為空 case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ClientHello; // 客戶端發(fā)送支持的TLS版本、客戶端隨機(jī)數(shù)、支持的加密套件等信息
服務(wù)器端回應(yīng)客戶端握手請求
服務(wù)器端收到 ClientHello 后,如果支持客戶端的TLS版本和算法要求,則返回 ServerHello, Certificate, CertificateRequest, ServerHelloDone 報文
struct { ProtocolVersion server_version; // 服務(wù)端最后決定使用的TLS版本 Random random; // 與客戶端隨機(jī)數(shù)算法相同,但是必須是獨立生成,與客戶端毫無關(guān)聯(lián) SessionID session_id; // 確定的會話ID CipherSuite cipher_suite; // 最終決定的加密套件 CompressionMethod compression_method; // 最終使用的壓縮算法 select (extensions_present) { // 額外插件,為空 case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ServerHello; // 服務(wù)器端返回最終決定的TLS版本,算法,會話ID和服務(wù)器隨機(jī)數(shù)等信息 struct { ASN.1Cert certificate_list<0..2^24-1>; // 服務(wù)器證書信息 } Certificate; // 向客戶端發(fā)送服務(wù)器證書 struct { ClientCertificateType certificate_types<1..2^8-1>; // 證書類型,本次握手為 值固定為rsa_sign SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>; // 支持的HASH 簽名算法 DistinguishedName certificate_authorities<0..2^16-1>; // 服務(wù)器能認(rèn)可的CA證書的Subject列表 } CertificateRequest; // 本次握手為雙向認(rèn)證,此報文表示請求客戶端發(fā)送客戶端證書 struct { } ServerHelloDone // 標(biāo)記服務(wù)器數(shù)據(jù)末尾,無內(nèi)容
客戶端收到服務(wù)器后響應(yīng)
客戶端應(yīng)校驗服務(wù)器端證書,通常用當(dāng)用本地存儲的可信任CA證書校驗,如果校驗通過,客戶端將返回 Certificate, ClientKeyExchange, CertificateVerify, change_cipher_spec, Finished 報文。
CertificateVerify 報文中的簽名為 Ukey硬件簽名 , 此外客戶端證書也是從Ukey讀取。
struct { ASN.1Cert certificate_list<0..2^24-1>; // 服務(wù)器證書信息 } Certificate; // 向服務(wù)器端發(fā)送客戶端證書 struct { select (KeyExchangeAlgorithm) { case rsa: EncryptedPreMasterSecret; // 服務(wù)器采用RSA算法,用服務(wù)器端證書的公鑰,加密客戶端生成的46字節(jié)隨機(jī)數(shù)(premaster secret) case dhe_dss: case dhe_rsa: case dh_dss: case dh_rsa: case dh_anon: ClientDiffieHellmanPublic; } exchange_keys; } ClientKeyExchange; // 用于返回加密的客戶端生成的隨機(jī)密鑰(premaster secret) struct { digitally-signed struct { opaque handshake_messages[handshake_messages_length]; // 采用客戶端RSA私鑰,對之前所有的握手報文數(shù)據(jù),HASH后進(jìn)行RSA簽名 } } CertificateVerify; // 用于服務(wù)器端校驗客戶端對客戶端證書的所有權(quán) struct { enum { change_cipher_spec(1), (255) } type; // 固定值0x01 } ChangeCipherSpec; // 通知服務(wù)器后續(xù)報文為密文 struct { opaque verify_data[verify_data_length]; // 校驗密文,算法PRF(master_secret, 'client finished', Hash(handshake_messages)) } Finished; // 密文信息,計算之前所有收到和發(fā)送的信息(handshake_messages)的摘要,加上`client finished`, 執(zhí)行PRF算法
Finished 報文生成過程中,將產(chǎn)生會話密鑰 master secret,然后生成Finish報文內(nèi)容。
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) verify_data = PRF(master_secret, 'client finished', Hash(handshake_messages))
PRF為TLS v1.2規(guī)定的偽隨機(jī)算法, 此例子中,HMAC算法為 SHA256
PRF(secret, label, seed) = P_(secret, label + seed) P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + HMAC_hash(secret, A(2) + seed) + HMAC_hash(secret, A(3) + seed) + ... // A(0) = seed // A(i) = HMAC_hash(secret, A(i-1))
服務(wù)器完成握手
服務(wù)收到請求后,首先校驗客戶端證書的合法性,并且驗證客戶端證書簽名是否合法。根據(jù)服務(wù)器端證書私鑰,解密 ClientKeyExchange,獲得pre_master_secret, 用相同的PRF算法即可獲取會話密鑰,校驗客戶端 Finish 信息是否正確。如果正確,則服務(wù)器端與客戶端完成密鑰交換。 返回 change_cipher_spec, Finished 報文。
struct { enum { change_cipher_spec(1), (255) } type; // 固定值0x01 } ChangeCipherSpec; // 通知服務(wù)器后續(xù)報文為密文 struct { opaque verify_data[verify_data_length]; // 校驗密文,算法PRF(master_secret, 'server finished', Hash(handshake_messages)) } Finished; // 密文信息,計算之前所有收到和發(fā)送的信息(handshake_messages)的摘要,加上`server finished`, 執(zhí)行PRF算法
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。