Избегайте отправки TLS_EMPTY_RENEGOTIATION_INFO_SCSV-шифра в TLS-клиенте Hello

Node.js по умолчанию шифрует TLS_EMPTY_RENEGOTIATION_INFO_SCSV, чтобы защитить себя от атаки POODLE.

Я пытаюсь избежать отправки этого шифрования (даже если это может представлять угрозу безопасности) путем переопределения шифров TLS с помощью специального списка шифров.

Однако Node.js продолжает отправлять TLS_EMPTY_RENEGOTIATION_INFO_SCSV шифр независимо от того, что я делаю. Я пытаюсь сознательно избегать отправки этого шифра, чтобы имитировать TLS-согласование Firefox/Chrome.

Вот код, который я использую для изменения и проверки того, какие шифры Node отправляет:

var request = require('request');

var ciphers = [
    'ECDHE-ECDSA-AES128-GCM-SHA256',
    'ECDHE-RSA-AES128-GCM-SHA256',
    'ECDHE-ECDSA-AES256-SHA',
    'ECDHE-ECDSA-AES128-SHA',
    'ECDHE-RSA-AES128-SHA',
    'ECDHE-RSA-AES256-SHA',
    'DHE-RSA-AES128-SHA',
    'DHE-RSA-AES256-SHA',
    'AES128-SHA',
    'AES256-SHA',
    'DES-CBC3-SHA'
].join(':');

var options = {
    ciphers: ciphers,
    secureProtocol: 'TLSv1_2_method',
    url: 'https://www.howsmyssl.com/a/check'
};

request(options, function (error, response, body){
    if (!error) {
        console.log(body);
    }
    else {
        console.log(error);
    }
});

Можно ли отключить отправку этого шифра в Node.js?

Ответ 1

Учитывая, что эта проблема связана с Node.js, есть один простой способ справиться с вашей проблемой, не вникая в нее в основном:

Поместите веб-прокси перед процессом Node.js и позвольте ему обрабатывать полное SSL-соединение. В самом коде Node.js вы отправляете запрос только на локальный HTTP-сервер.

Пример конфигурации с nginx (внутри директивы http):

server {
   listen 8080;
   location / {
      resolver 8.8.8.8;
      proxy_pass https://www.howsmyssl.com$uri$is_args&args;
      proxy_ssl_protocols TLSv1.2;
      proxy_ssl_ciphers AESGCM:!aNULL;
   }
}

И измените nodejs на:

var request = require('request');

var options = {
    url: 'http://localhost:8080/a/check'
};

request(options, function (error, response, body){
    if (!error) {
        console.log(body);
    }
    else {
        console.log(error);
    }
});

К сожалению, хотя я и сделал это, и результат был таким же:

{"given_cipher_suites":["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_DH_DSS_WITH_AES_256_GCM_SHA384","TLS_DHE_DSS_WITH_AES_256_GCM_SHA384","TLS_DH_RSA_WITH_AES_256_GCM_SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_DH_DSS_WITH_AES_128_GCM_SHA256","TLS_DHE_DSS_WITH_AES_128_GCM_SHA256","TLS_DH_RSA_WITH_AES_128_GCM_SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_EMPTY_RENEGOTIATION_INFO_SCSV"],"ephemeral_keys_supported":true,"session_ticket_supported":true,"tls_compression_supported":false,"unknown_cipher_suite_supported":false,"beast_vuln":false,"able_to_detect_n_minus_one_splitting":false,"insecure_cipher_suites":{},"tls_version":"TLS 1.2","rating":"Probably Okay"}

Это в основном означает, что его, вероятно, стандартное поведение OpenSSL.

Есть опции, которые можно установить в OpenSSL, используя SSL_CTX_set_options

Особенно интересным здесь является раздел SECURE RENEGOTIATION и этот вариант:

SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION

Разрешить устаревшее небезопасное переключение между OpenSSL и непроверенными клиентами или серверами. Дополнительную информацию см. В разделе SECURE RENEGOTIATION.

Я не уверен, что если это фактически предотвратит отправку пересмотренного шифрования. Если эта опция действительно правильная, может быть способ либо запланировать Node.js, чтобы использовать эту опцию, либо перекомпилировать OpenSSL с этой опцией.

Разумеется, также будет возможность использовать старую неподдерживаемую версию. Из моего понимания, хотя TLS_EMPTY_RENEGOTIATION_INFO_SCSV не связано с POODLE, но из более старого исправления:

CVE-2009-3555 (консультация OpenSSL) 5 ноября 2009 года:
Внедрите RFC5746 для устранения уязвимостей в повторном соглашении SSL/TLS. Исправлено в OpenSSL 0.9.8m (Потери 0.9.8l, 0.9.8k, 0.9.8j, 0.9.8i, 0.9.8h, 0.9.8g, 0.9.8f, 0.9.8e, 0.9.8d, 0.9.8c, 0.9. 8b, 0,9,8a, 0,9,8)

Современный Node.js поставляется со статически связанным OpenSSL и не поддерживает OpenSSL 0.9.8, поэтому вам понадобится более старая версия Node.js независимо... или использовать материал nginx с незагруженным OpenSSL...

Это то место, где я застрял. Это не совсем полный ответ, но я думаю, что его, по крайней мере, стоит разделить.

Подводя итог, я думаю, что если вы захотите сделать это без перекомпиляции, используйте nginx с открытым и открытым файлом OpenSSL и настройте несколько серверов, по одному для каждого клиента, который вы хотите имитировать.

Если вам требуется, чтобы это было выполнено в node, лучше всего установить исправление OpenSSL прямо и перекомпилировать Node.