节点js https minDHSize不关闭连接

node js https minDHSize not closing connection

我正在向提供 2048 位 Diffie-Hellman 密码的服务器发出 https 请求,并试图让我的代码拒绝连接并将握手失败发回服务器并关闭连接。我不认为它被使用,但我在客户端有一个 4096 位 DH 密钥,如果服务器也使用 4096 位 DH 密钥,连接就完美了。

const dhparam = fs.readFileSync( "dhparam_4096.pem" );
const data = JSON.stringify({ 
    part1 : "Hello", 
    part2 " "Name" });
const httpsOptions = {
    host : address + "%" + Ethernet.GetIfaceName(),
    port : service.port,
    path : service.txt.path,
    method : "PUT",
    rejectUnauthorized : false,
    ciphers : "ADH-AES256-GCM-SHA384:@SECLEVEL=0",
    dhparam,
    minDHSize : 4096,
    headers : { 
       'Content-Type' : 'application/json',
       'Content-Length' : data.length,
    },
    servername : "nameServer",
}
console.log( "    httpsOptions =", httpsOptions );
                        
/*** Send the request ***/
                        
var req = https.request( httpsOptions, res => 
{
    var data = "";
    res.on( 'data', d => data += d );
    res.on( 'end', d =>  
    { 
        if ( d ) data += d;
        console.log( "Received data =", data );
        console.log( "    ", data.toString() );
    });
    console.log( "response =", res.statusCode, res.statusMessage );
});

req.on( "error", err => 
{
    console.log( "error =", err.code );
    if ( err.code === "ERR_TLS_DH_PARAM_SIZE" )
    {
        console.log("    DH Key is not 4096 bits" );
        req.socket.destroy();
    }
                           
});
console.log( "    sending data: ". data );
req.write( data );
req.end();

minDHSize : 4096 导致错误事件被触发,所以我知道检测机制正在工作。

我在这个路径中有一个 socket.destroy(),但它似乎不起作用。

在服务器上,我启用了跟踪,并得到以下信息:

Received Record
Header:
  Version = TLS 1.0 (0x301)
  Content Type = Handshake (22)
  Length = 153
    ClientHello, Length=149
      client_version=0x303 (TLS 1.2)
      Random:
        gmt_unix_time=0xFE471FB1
        random_bytes (len=28): 3B54266D9E916B151A9A8E940EE4D0BEE0E59C1F2693B6E637CC4D
      session_id (len=0): 
      cipher_suites (len=4)
        {0x00, 0xA7} TLS_DH_anon_WITH_AES_256_GCM_SHA384
        {0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
      compression_methods (len=1)
        No Compression (0x00)
      extensions, length = 104
        extension_type=server_name(0), length=36
        extension_type=session_ticket(35), length=0
        extension_type=encrypt_then_mac(22), length=0
        extension_type=extended_master_secret(23), length=0
        extension_type=signature_algorithms(13), length=48
          ecdsa_secp256r1_sha256 (0x0403)
          ecdsa_secp384r1_sha384 (0x0503)
          ecdsa_secp521r1_sha512 (0x0603)
          ed25519 (0x0807)
          ed448 (0x0808)
          rsa_pss_pss_sha256 (0x0809)
          rsa_pss_pss_sha384 (0x080a)
          rsa_pss_pss_sha512 (0x080b)
          rsa_pss_rsae_sha256 (0x0804)
          rsa_pss_rsae_sha384 (0x0805)
          rsa_pss_rsae_sha512 (0x0806)
          rsa_pkcs1_sha256 (0x0401)
          rsa_pkcs1_sha384 (0x0501)
          rsa_pkcs1_sha512 (0x0601)
          ecdsa_sha224 (0x0303)
          ecdsa_sha1 (0x0203)
          rsa_pkcs1_sha224 (0x0301)
          rsa_pkcs1_sha1 (0x0201)
          dsa_sha224 (0x0302)
          dsa_sha1 (0x0202)
          dsa_sha256 (0x0402)
          dsa_sha384 (0x0502)
          dsa_sha512 (0x0602)


Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 57
    ServerHello, Length=53
      server_version=0x303 (TLS 1.2)
      Random:
        gmt_unix_time=0xDB67568F
        random_bytes (len=28): BF81EBFB16471C15ED8D7D0D5273232CFBD6E70E933CC00747B57899
      session_id (len=0): 
      cipher_suite {0x00, 0xA7} TLS_DH_anon_WITH_AES_256_GCM_SHA384
      compression_method: No Compression (0x00)
      extensions, length = 13
        extension_type=renegotiate(65281), length=1
            <EMPTY>
        extension_type=session_ticket(35), length=0
        extension_type=extended_master_secret(23), length=0

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 523
    ServerKeyExchange, Length=519
      KeyExchangeAlgorithm=DHE
        dh_p (len=256):     C0C8B68E3EAADEB2ECCA8863B8017D63D3259FEC711A97D84E8100DC427BA45684DF962C00C8116DCE797BD02CA3D02FB2C01F7F212AA1E899CB108A57156841A1CE40F4E2EF65AC1598964851F4DB874BD9E8031B2467B7624CE3CC950B0167C23A91896CAF44199B45A046A9EA1D274D6545AC1AC11542ED9F1C0CA3F8DDF5CB215436C3416FFE20242AA5C3270858D07314C58478F771D201B54D47DFAFD87F127FC3E8C11F40CE5B1A063AF7C6C50347C3049A9EE479EA685499E57A49DE1287DC96AE71E0E7F10B42BB09DC8BAFBE96F710FE20F0FC296C1D951CD258946E1AEF5876494B524809B14F12F393B40AEF0BD4E44F6E67E8A579184CAB393B
        dh_g (len=1): 02
        dh_Ys (len=256): AE3E9B2D557F7A862D323911B17061471865880B8CDA469D94CCEC11A74B6C081A2F0389BF2B961E5A54C7A6DE41D1AFB9388B5BB51EC6F129BA093A83DA68288D5246869B52B54D2CF5CD0F1BDEAA206FC7C680B02B18903969B061817479545BF8EA17901CF86A9E580DF860FD29E25A2EB56D00FE319D2DA17F9E3F33986D4716D86882E76E774A7CB717AD08E60AA182843B139E6EFB63F2EFCD6E351503352F3E5A23D397AAA4BB359A8EF125FF10FE20805B083B15135247E1B08F57B3B43EF13E9B60EEB2EB1743466DD10922ABD588E9031BC1BDF10353484BC10B2E32D24E513E58092373E96360836BE4FFDC3395CB4044BCEE11248E0E5EDA412F

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 4
    ServerHelloDone, Length=0

Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 262
    ClientKeyExchange, Length=258
      KeyExchangeAlgorithm=DHE
        dh_Yc (len=256): 060D2565ABCE52B7480CB72D2DEF6F5B8FC25B15FB070BB97DC0B509143CFC562BF8483D24959B8192B292DE1D17FBEB281734DF062F48313AEBE3F1398EC9C535086D3DBDB7F2F52FB1F656B078908520B2B2285F2382C16E0731AAF00CAF098EBB32AE89CEB50940BA1EBE8A08EF86739CFC6DABD9965E9D2325DA73F53045C686C74006A525A35E27180D51BED9EEB9831EF617C7D78AF19CCBB6EE9F016911E1C2F0D9CEF6F3E31E14109EFDBF1187720AA34324C94CB166DAAA4D2E69D1182D5B86C8F1EA89FB02C5E9420DFC333ABBA4050F8C782F1B16B74F87F0251B06B4D725FC6FE26B3FC5C2CB54FBA94174576F694A02D1FC707BABD2E03FB854

Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ChangeCipherSpec (20)
  Length = 1
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 40
    Finished, Length=12
      verify_data (len=12): DCA9352457FDBF48674FE0B8

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 202
    NewSessionTicket, Length=198
        ticket_lifetime_hint=7200
        ticket (len=192): 06B807C486272F454FC553528EC5B6932A5989321D4171F7A6DAF4A2F0E9FA9A3620F9F90499FF5FD7C2566D4A5E7574DD6863353CC428E7656168799B3501613A67AF605746F034571AA9264A53A3DCCE4CACCB72FA54FF9B4C735666F4FA0AEC56A6F8819E375BEC01DC9FC282052E4FBFF88D07596247CE2AC92870B4CE759D946FD18E78B48EBF4474F9D6D51BB6924662B9CB3A312E9D7AD76B97C335A07531841F2D7A5A02BCBCE4857EE43626FF07CD4D44937CFF74401FFE2787740C

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ChangeCipherSpec (20)
  Length = 1
    change_cipher_spec (1)

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 40
    Finished, Length=12
      verify_data (len=12): E72603E1A716815F94F9AAEE

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Alert (21)
  Length = 26
    Level=warning(1), description=close notify(0)

没有来自客户端的消息表明握手失败,TCP 连接尚未关闭。

我错过了什么?

There is no message coming from the client to indicate a handshake failure and the TCP connection has not been closed.

这样的握手不会失败。 OpenSSL 无法在密钥交换中要求最小经典 DH 大小(对于 DHE 和 OpenSSL 调用 ADH 的 DH_anon),因此 nodejs 在 after 之后实施此限制OpenSSL 完成握手 但在允许任何数据通过之前——因为它也对服务器证书名称检查进行,OpenSSL 最初没有实现,现在实现与 nodejs 选择的不同。参见 onSecureConnect in _tls_wrap.js

TCP 连接已关闭,这可能是为什么您的服务器正在发送close_notify——或试图;由于 TCP 关闭,此发送实际上会失败。我测试的服务器(OpenSSL 和 Java)都显示 TCP 从(nodejs)客户端关闭,尽管 OpenSSL 是隐式这样做的(读取计数为 0),并且它们的响应不同:只有较旧的 Java 8 (在 8u261 中向后移植新的 11 堆栈之前)尝试在 'response' 中发送 close_notify。我怀疑您的服务器只是没有记录 TCP 关闭;试试 wireshark 或类似的外部工具。

需要说明的是,你在客户端设置的4096位DH参数,不是密钥。服务器只设置参数;两端的密钥都是在每次握手时生成的(在参数定义的子组中),这就是它们被称为临时密钥的原因。 客户端 中设置的(用户选择的)DH 参数被忽略(但请参阅下一个)。

仅供参考:有一个相当新的协议选项 RFC7919,用于 TLS1.2* 使用标准化(非用户选择)DHE/anon 组,现在称为 FFDHE 以区别于 ECDHE,客户端可以以前 supported_curves 扩展名的请求现在被重新调整为 supported_groups (特别是它可能需要 4096),但是 OpenSSL 和 nodejs 没有实现这个选项。在 1.3 中 supported_groups 是必需的,但 FFDHE 组不是必需的,甚至不是特别鼓励的,而且 AFAICT OpenSSL 也不(还?)在那里支持它们——而且无论如何 1.3 不允许 'anon'根本。 (* 7919 正式适用于 1.1 和 1.0,但我无法想象任何实现包括 7919 而不是 1.2,因此您永远不需要更低的协议。)