Избегайте отправки шифра TLS_EMPTY_RENEGOTIATION_INFO_SCSV в TLS Client 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?


person Elad Nava    schedule 07.02.2016    source источник
comment
Я думаю, что это не связано напрямую с node.js, а с модулем запроса, который вы используете. Или вы отладили проблему в ядре node.js?   -  person crackmigg    schedule 07.02.2016
comment
Я не уверен, что это правильно: ... в отправке этого шифра нет необходимости, если я намеренно отключаю понижение версии протокола (путем принудительного использования TLS 1.2. Я считаю, что все версии TLS подвержены атакам перехода на более раннюю версию, потому что TLS делает не использовать пару версий {min-TLS,max-TLS}. Вместо этого _ 2_ работает с течением времени, поэтому он будет применяться к последовательным соединениям, а не к одной попытке соединения в вакууме.   -  person jww    schedule 07.02.2016
comment
@migg он находится в ядре Node.js - проверьте ssl_lib.c # L1472, который, по-видимому, является тем местом в Node.js, где шифр SCSV добавляется к Client Hello (я могу ошибаться насчет строки, но он находится в этом файле). Модуль request npm зависит от пакета tls в Node.js, который обрабатывает TLS-соединение через openssl. @jww, возможно, вы правы в том, что это небезопасно, однако я все же хотел бы отключить его для тестового примера и не беспокоиться о последствиях для безопасности в настоящее время.   -  person Elad Nava    schedule 08.02.2016


Ответы (2)


Учитывая, что эта проблема связана с 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.

Особенно интересен здесь раздел БЕЗОПАСНАЯ ПЕРЕЕГОВОРКА и такая опция:

SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION

Разрешить устаревшее небезопасное повторное согласование между OpenSSL и непропатченными клиентами или серверами. См. Раздел БЕЗОПАСНАЯ ПЕРЕНОСКАНИЕ для более подробной информации.

Однако я не уверен, действительно ли это препятствует отправке шифра повторного согласования. Если эта опция действительно верна, возможно, есть способ исправить 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 без исправлений и настройте несколько серверов, по одному для каждого клиента, которого вы хотите имитировать.

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

person Nappy    schedule 16.02.2016
comment
Это путь. Я всегда позволяю Ngnix обрабатывать мой SSL - гораздо меньше риска проблем в будущем. - person David Betz; 16.02.2016
comment
Большое спасибо за подробный ответ! Я думаю, что в конечном итоге я исправлю Node.js и скомпилирую его вручную, поскольку мне не удалось избежать отправки этого шифра даже на node 0.8.x. - person Elad Nava; 17.02.2016

Кажется, что TLS_EMPTY_RENEGOTIATION_INFO - это набор шифров-заполнителей, который выполняет ту же функцию, что и renegotiation_info расширения. Кроме того, похоже, что OpenSSL не имеет возможности установить расширение renegotiation_info и что этот пустой Cipher Suite необходим.

Источник: c-openssl-setting-list-of-ciphers
Источник: RFC 5746 Section-3.3

person Stryker2k2    schedule 26.05.2021