Бронируем TLS в Windows Server 2012 R2

Новая статья по защите и настройке протоколов SSL/TLS в нашей базе полезной информации, Knowledge Base

Привет.

Защита TLS – штука крайне нужная. У неё много аспектов – как безопасность самой хостовой ОС, на которой развёрнут веб-сервер, так и безопасность работающих приложений, криптографические аспекты и многое другое. Я попробую написать про то, что с моей точки зрения, является важным и не сильно документированным / очевидным. На этом вода про то, что с TLS лучше, чем без TLS, а с настроенным TLS лучше, чем с не настроенным TLS, официально объявляется закончившейся.

Стартовые ограничения статьи – не будет рассматриваться тюнинг SSL, т.к. уже 13 лет как есть TLS, SSL мы будем выключать полностью. Не будет рассматриваться настройка систем младше NT 6.0, т.к. про это можно найти в предыдущей статье, да и те, кто думает о безопасности TLS, наружу Windows Server 2003й в 2014м году не выставляет.

Для большинства операций я буду использовать ATcmd – им проще делать тонкий тюнинг SSL/TLS. Если хотите – можете найти другие методы по выполнению аналогичных действий на своей ОС, это некритично – функционал называется стандартно, и ту же фрагментацию TLS можно настраивать чем удобно.

Бронируем TLS в Windows Server 2012 R2

  • Версия SSL/TLS на сервере
  • Отключаем неиспользуемые версии SSL/TLS и PCT/MPUH
  • Пересогласование TLS
  • Фиксируем только нужные cipher suites
  • Блокируем небезопасные криптоалгоритмы
  • Настраиваем фрагментацию TLS
  • SSL Close-Notify
  • Журналирование TLS
  • Отправка клиенту списка доверенных CA в CTL-формате
  • Логика проверки x.509-сертификата клиента
  • Проверка промежуточных сертификатов через Интернет
  • Механизм HSTS – HTTP Strict Transport Security
  • Кэшируем SSL/TLS-сессии – используя Session ID
  • Кэшируем SSL/TLS-сессии – используя Session Tickets

Поехали.

Версия SSL/TLS на сервере

Первым делом – проведём инвентаризацию того, что умеет поддерживать SCHANNEL в Windows NT. Это будут:

  • Очень старый и просто старый варианты SSL – 2.0 и 3.0
  • Редкие и давно устаревшие PCT 1.0 и MPUH
  • Протоколы TLS 1.0, TLS 1.1, TLS 1.2 и их варианты для работы поверх UDP – DTLS 1.0 и DTLS 1.2

Разберемся по порядку.

Краткая история вопроса – SSL

Протокол SSL был разработан фирмой Netscape, достаточно давно. Я осознанно пропущу исторические подробности, так как они сейчас уже не особо интересны. В его задачи входило следующее:

  • Обязательность подтверждения подлинности сервером
  • Опциональная проверка подлинности клиента
  • Совместная генерация случайного сеансового ключа
  • Поддержка различных симметричных алгоритмов для шифрования данных
  • Поддержка различных алгоритмов хэширования для реализации проверки целостности через MAC

Первая версия SSL не особо показывалась публике, отсчёт рабочих версий можно начинать с SSL 2.0 (1995й год). Эта версия была первой, которая эксплуатировалась в production, и достаточно оперативно она была доработана до SSL 3.0. Заметим, что хотя это произошло достаточно давно – в 1996 году – стандарт от этого не стал общим и открытым; он оставался стандартом, разработанным конкретной фирмой Netscape, и для его использования в ряде случаев нужна была лицензия. Опубликован IETF он был недавно; RFC 6101 описывает то, что 15 лет уже стандарт де-факто для защиты сессий множества приложений. Но, по сути, с ним уже давно пора прощаться; TLS существует годы (с 1999, если быть точнее). Поддержка TLS 1.0 есть уже во всех, даже устаревших, продуктах, поэтому мы будем в явном виде отключать SSL. Пора уже закопать стюардессу.

Краткая история вопроса – PCT 1.0 и MPUH

Протокол Private Communications Technology был разработан Microsoft’ом, чтобы улучшить работу SSL 2.0 и, на самом деле, был совместим с оным в плане формата negotiation, работал лучше и безопаснее. Но важнее то, что он подтолкнул разработку TLS. Ведь по сути, на 1995й год (тогда и был предложен драфт этого протокола на стандартизацию) ситуация была простой – SSL был частной инициативой Netscape, веб нуждался в подобном стандарте, и то, что ещё один вендор начал делать “Такое же, но чуть лучше, и своё” подтолкнуло к пониманию, что если это продолжить, то будет плохо всем – будет пачка разных вариантов от разных вендоров, частично совместимая и закрытая. Это бы затормозило развитие технологий безопасной работы в Интернете, поэтому PCT благополучно похоронили, а через 3 года появился TLS. Поэтому PCT мы будем отключать в явном виде (хоть это и делается автоматически с ядра NT 6.0, но лучше сделать это явно и жестко, чем оставить на самотёк).

Multi-Protocol Unified Hello – ещё одна древняя попытка Microsoft сделать универсальный безопасный протокол типа SSL. Она совсем древняя, поэтому её тоже надо выключать в явном виде – просто чтобы исключить даже попытки её согласовать или предложить.

Краткая история вопроса – TLS 1.0, 1.1 и 1.2

В 1999 году появляется TLS 1.0. Он заменяет собой вендорский SSL 3.0, являсь очень похожим на него, и пишет в заголовок версию {0x03,0x01}, намекая, что он 3.1.

Версия 1.0, по сути, является базовой, хотя, надо отметить, напрямую TLS 1.0 и SSL 3.0 не совместимы; TLS 1.0 “умеет” работать в режиме совместимости с SSL, но именно в режиме, а не “идентично”, как иногда можно прочитать.
Например, у SSL 3.0 есть встроенная в протокол неприятность – половина master key будет создаваться из MD5-хэша достаточно предсказуемых данных, что может привести (учитывая текущее положение MD5) к успешной коллизионной атаке (в результате станет известна половина бит мастер-ключа, от которого после генерятся сессионные ключи, а это практически равнозначно компрометации процесса). У TLS 1.0 это поправили, и схема усложнена – PRF-функцией берутся и MD5 и SHA-1 хэши, после чего xor’ятся, что сводит возможность вышеуказанной атаки к нулю. Кстати, из-за этого момента в алгоритме – завязанности ключевой части процесса на MD5, SSL 3.0 не является FIPS140-2 совместимым и при включении FIPS140-2 не согласовывается, а вот TLS 1.0 – уже является. Что же ещё, помимо FIPS-совместимости и модификации PRF-функции?

  • Убрана поддержка cipher suites с алгоритмом Fortezza
  • Клиент обязан поддерживать cipher suite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA. То есть, обязательна реализация 3DES у клиента.
  • В TLS явно и недвусмыслено описали, как именно делается padding в блочных шифрах (т.е. чем “добиваются” блоки некратной длины в CBC-варианте) – это как раз то, из-за чего для борьбы с уязвимостью POODLE (детали про неё можно посмотреть здесь) нужно отключать поддержку SSLv3.
  • В SSL не было явно указано, как защищать pre-master secret. В TLS – формализовали, поэтому разные реализации стали делать это однотипно.
  • В TLS гораздо больше возможных alert’ов со стороны сервера, поэтому клиенту “понятнее” и причины отбоя со стороны сервера, и другие проблемы при handshake.
  • Поддержка возможности получить корневой сертификат в составе certificate_list с сервера – в SSL можно было получить лишь intermediate.
  • В SSL у клиента была возможность отправлять данные некоторое время после отправки Finished. В TLS это убрали.

Поддержка TLS 1.0 сейчас является абсолютным минимумом для защищённых соединений – но со времён 1.0 много воды утекло и многое поменялось – смотрим дальше.

Промежуточными дополнительными расширениями, интересными для нас, будут RFC 3268 от 2002 года, который добавляет поддержку AES (двух основных вариантов – с 128 и 256 битами, третий штатный вариант со 192 как-то не особо прижился), и RFC 3546 от 2003 года, который добавляет пачку extension’ов, включая в себя расширение механизма handshake, добавление SNI (Server Name Indication), согласования размера TLS-фрагмента и расширенной работы с сертификатами и CRL. Его расширяет RFC 4366 от 2006 года, который добавляет ещё расширений – про них упомянём далее.

В 2006 году появляется TLS 1.1. Что он меняет?

Основное в нём – защита от найденных проблем с атаками на блочные шифры, работающие в CBC-режиме.

  • Вектор инициализации ранее считался из остатка после CBC-шифрования предыдущего блока данных. Теперь он явный и прямой зависимости от результата предыдущего шифрования не имеет.
  • Улучшена обработка padding errors – они теперь вычисляются на уровне “не совпал MAC”, а не “сбой расшифровки”, что улучшает отделение попыток атаки от технических сбоев.
  • Улучшена поддержка session resuming – возможности продолжить прерванную сессию без полной переустановки и пересогласования.

Таким образом, TLS 1.1 – некрупный багфикс TLS 1.0, поддержка которого никак особо не перегружает сервера (это я про миф про то, что “мы не держим TLS старше 1.0, потому что он дико грузит серваки”), но закрывает явно существующие уязвимости. Что далее?

В 2008 году появляется TLS 1.2. Он привносит следующие полезные штуки:

  • Связка MD5+SHA-1, используемая в предыдущих версиях, и пришедшая на замену одинокому MD5 в семействе SSL, теперь может быть заменена любым хэш-алгоритмом (предпочтительным является представитель семейства SHA-2, в частности SHA-256)
  • Поле Verify_data, по сути – PRF (PRF = pseudorandom function = почти KDF, только KDF-функция делает из чего-то ключ, а PRF рандомизирует несколько входных блоков данных в один) от master_secret, MD5 и SHA-1 хэшей данных и строчки finished_label (которая может быть или “server_finished” или “client_finished”), теперь мало того, что считается с нужным хэшем, так ещё и перестало быть ограничено 12ю байтами. Т.е. ранее от всего этого брались последние 96 бит, а теперь – столько, сколько надо, что соответственно усиливает надёжность проверки целостности данных.
  • Серьёзные изменения в криптографической части. Хэши семейства SHA-2 теперь обязательны к поддержке, а SHA-256 – рекомендуемый минимальный. Убрана поддержка алгоритмов IDEA и DES – с ними теперь TLS-сессию не согласовать, сервер откажется. Обязательным для поддержки стал cipher suite TLS_RSA_WITH_AES_128_CBC_SHA, без его наличия клиента не подключат.
  • Множественные доработки в самом алгоритме, коснувшиеся ужесточения порядка действий (отсекая потенциальные атаки, связанные с излишней гибкостью поведения алгоритма ранее), увеличения количества ситуаций, когда сервер высылает клиенту alert с описанием проблемы, а не просто отключает или игнорит блок данных. Например, теперь клиент, если у него нет сертификатов, а его запросили, не может промолчать, а обязан выслать ответ с пустым списком сертификатов.

В алгоритме также сделана необязательной поддержка SSL 2.0, а впоследствии, в 2011 году, в RFC 6176, SSL 2.0 практически отключается – клиенту явно запрещается посылать hello-запросы с протоколом ниже {0x03, 0x00}, серверу тоже запрещается их отправлять, а если к серверу они всё же приходят, он будет их игнорировать. Говоря про TLS 1.2 мы будем подразумевать его в варианте “учитывая RFC 6176”.

Фактически, TLS 1.2 – это линейное улучшение криптографических параметров TLS предыдущих версий, явное отсечение устаревших функций плюс ещё бОльшая формализация алгоритма.

После TLS 1.2 развитие TLS также не остановилось – RFC 5746 добавляет новый вариант безопасного пересогласования ключевой информации, а RFC 5878 – новые расширения для новых типов авторизации, ну а RFC 6066 актуализирует эти, ставшие уже стандартными, расширения.

Отдельно можно добавить то, что оригинальные протоколы – SSL, PCT, TLS – были нацелены на защиту TCP-трафика, но параллельно с реализацией TLS появился и DTLS, предназначенный для защиты потока датаграмм юникастового трафика (это UDP, SCTP, DCCP и RTP). В плане функционала версий DTLS 1.0 – это TLS 1.1, а DTLS 1.2 – TLS 1.2. Технически в плане безопасности отличий в нём будет минимум, поэтому отдельно про него писать не будем, упомянём лишь, что “из коробки” он доступен начиная с ядра NT 6.2, а для предыдущего поколения ОС доступен добавляющий его поддержку (только для UDP) в SCHANNEL патч – KB 2574819. Это нужно, например, для работы RDP 8.0, который умеет работать поверх UDP.

Так что материала много – вперёд, к практике.

Отключаем PCT 1.0, MPUH, SSL 2.0 и SSL 3.0

Итак, теперь практика – выключаем совсем SSL 2.0, SSL 3.0, PCT 1.0, MPUH, включаем в явном виде TLS 1.1 и TLS 1.2. С TLS 1.0 ситуация на Ваш выбор – хорошо бы его, конечно, выключить, но надо убедиться, что клиенты это выдержат. В первую очередь это коснётся мобильных клиентов, где (особенно в Android) зоопарк полуработающих реализаций TLS – дело нормальное. Хотя и десктопные не отстают – в той же Filezilla, использующей gnutls, реализацию допилили до полностью RFCшной только летом 2013го года – для примера, у Microsoft это было с Windows Server 2008R2, т.е. с 2009 года. Ну, опенсорс – роль догоняющего-допиливающего-на-бегу-чтобы-хоть-кое-как-работало для них привычная, так что ничего сверхординарного.

Запустим ATcmd и выключим-включим нужное – для этого зайдём в контекст tls, потом в субконтекст protocols и выполним удобную команду onlytls:
Выключаем все SSL, MPUH и PCT и явно включаем TLS

Посмотрим на результаты, выполнив команду show tls:

Смотрим состояние протоколов SSL, MPUH, PCT и TLS на хосте

Вполне ОК. Теперь надо тюнить выживший TLS.

Пересогласование TLS

В TLS есть интересные дополнительные механизмы, которые нуждаются в настройке. Первый из них – это пересогласование. Суть достаточно простая – во всех протоколах, которые обеспечивают конфиденциальность данных, принято время от времени менять ключи, которые используются для этой задачи. Смена их может быть разной – как частичной (например, в IPsec без PFS – когда из одного ключевого материала периодически “нарезаются” разные ключи), так и полной (когда новый ключевой материал генерится каждый раз заново). Идея в том, что эта операция – смены ключей – крайне важна и её проведение практически всегда связано с нагрузкой на CPU. В классическом TLS пересогласование мог “заказать” клиент фактически в любой момент, что и использовалось для возможной атаки (т.е. можно подключиться к серверу и заставить его малыми усилиями со своей стороны постоянно и неограниченно делать сложные вычислительные задачи).

Безопасное пересогласование TLS описывается в стандарте RFC 5746 и решает проблему с этой возможной уязвимостью.

По сути, Windows-хост может работать в плане этого RFC в двух режимах – в режиме совместимости (т.е. допускать и небезопасное, “классическое” пересогласование TLS), и в “безопасном”, допуская только пересогласование в новом формате. По умолчанию, работа идёт в режиме совместимости. Это не всегда полезно, поэтому надо знать, как включать только безопасное пересогласование TLS.

Кроме того, в данном стандарте описывается специальный workaround для старых серверов, которые не поддерживают безопасное пересогласование – таким серверам отправляется специальный псевдо-cipher-suite, называемый Signaling Cipher Suite Value (SCSV), с кодом 0x00FF. Устаревший сервер проигнорирует этот неизвестный cipher suite, а клиент догадается, что сервер старый и не умеет новый безопасный renegotiation_info.

Вообще, если уж совсем закручивать гайки, то пересогласование надо выключать и, если уж оставлять, то только при TLS 1.2, потому что даже безопасное пересогласование при версиях TLS до 1.2й предоставляет шанс DoS на сервер. Но учитывайте – достаточно много софта этот вариант (выключение пересогласования) не переживёт. Поэтому мы включим только безопасный вариант пересогласования и явно выключим поддержку SCSV. Если она останется, то наш TLS будет посылать “заглушку” вместо запроса возможности безопасного пересогласования.

Т.е. суть наших настроек сейчас проста – мы предполагаем, что все сервера умеют работать с RFC 5746 (стандарт от 2010 года, так что времени уже прошло достаточно). Отмечу, что подобные настройки надо сделать и на серверах, которые инициируют TLS-подключение на другие хосты (например, почтовых), ведь в этом случае они выступают как клиенты.

Включаем поддержку TLS Renegotiation Indication Extension

В том же контексте tls у нас есть команда renego, которая по вопросику покажет, что она умеет:
Включаем безопасное пересогласование TLS
Выберем безопасный вариант, указав renego secure:
tls5

Явно выключаем SCSV

Ну и явно выключим SCSV:
Выключаем SCSV в TLS
С этим вроде всё. Понятное дело, если хочется супер-защиты, то надо renego none, если не TLS 1.2.

Дополнительно, из практики, добавлю, что не всё так однозначно в плане поддержки безопасного пересогласования TLS – допустим, сервера Office 365 не полностью поддерживают данный стандарт, поэтому если Вы включите только безопасное пересогласование TLS, то можете получить проблемы с “облачным” Lync 2013 – выглядеть эти проблемы будут как невозможность подключиться к демонстрации слайдов или whiteboard, в локальных логах Вы увидите событие 36888 от SCHANNEL, в котором будет сообщаться об ошибке TLS с кодом 40 и The Windows SChannel error state is 1207. Так что если видите что-то подобное – попробуйте восстановить настройки, опять включив “любое пересогласование”, а не только безопасное.

Фиксируем только нужные cipher suites

Итак, при согласовании TLS один из ключевых моментов – это выбор комплекта допустимых cipher suites. Вот как выглядит полный список поддерживаемых в CNG наборов:

TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P521
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P521
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P521
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P521
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_RC4_128_MD5
SSL_CK_RC4_128_WITH_MD5
SSL_CK_DES_192_EDE3_CBC_WITH_MD5
TLS_RSA_WITH_NULL_SHA
TLS_RSA_WITH_NULL_MD5

TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_NULL_SHA256

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521

Внушительно. Надо сокращать. Первым делом – убираем все те, кто содержит в себе:

    • SSL_ – варианты явно устарели и должны быть удалены, нет никакого смысла предъявлять их при согласовании что серверу, что клиенту.
    • TLS_RSA_ – во-первых при их согласовании не получится Forward Secrecy, во-вторых возможна потенциальная уязвимость FREAK, базирующаяся на использовании старых “экспортных” RSA.
    • Варианты с NULL – это когда согласуется “SSL без шифрования” – нам категорически не подходят.

 

    • DES / 3DES / RC4 – данные варианты на фоне ощутимо более быстрого и надёжного AES, который к тому же на современных процессорах аппаратно ускоряется, не интересны.

 

  • MD5 / SHA-1 – даже Windows XP и Windows Server 2003 с нужным патчем поддерживает хэши семейства SHA-2, поэтому нет смысла предлагать и поддерживать старые варианты, тем более, что выбор MD5, допустим, выглядит странно – учитывая, что даже в TLS 1.0 хэш был MD5+SHA-1, явный выбор одинокого MD5 – удивителен.

Для такого удаления неплохо подходит новый контекст ATcmd, который называется tls ciphersuites. В нём будет удобная команда clean, которая позволит прямо “на ходу”, без перезагрузки хоста и переприменения групповых политик, удалять из списка активных cipher suites нужные по какому-либо критерию. Например, так будет выглядеть удаление из списка согласуемых всех cipher suites, которые содержат в названии “DES”:

Удаление из списка согласовываемых TLS cipher suites по определённому критерию

tls7

Если что-то удалили зря – есть команда add, которая добавляет в верх списка (т.е. самым первым на согласование) указанный cipher suite.

Так вот, продолжим. Потенциальный список сразу сокращается:

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P521
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P521
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P521
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P521

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521

Не забудем в пылу борьбы, что для согласования TLS 1.0 надо обязательно оставить TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, а TLS 1.2 – TLS_RSA_WITH_AES_128_CBC_SHA. Т.е. в зависимости от того, включим ли мы TLS 1.0, нам придётся добавить первый из упомянутых либо нет. Список все равно внушительный, поэтому при его дальнейшем урезании будем исходить из следующих соображений.

    1. ECDHE лучше, чем DHE, благодаря дополнительной “степени защиты” в виде усложнения алгоритма генерации ключевого материала (при помощи эллиптических кривых). Плюс ECDHE быстрее. Генерация ключевого материала – по сути, самое важное, т.к. лобовая атака на AES – крайне маловероятна, а вот на предсказуемость генерации ключа – гораздо более реалистична. Мы не можем явно выбрать группу DH, а то бы, конечно, по меньшей мере отказались от групп 1,2,5 и выбрали бы 16, ну или 14-15, но нам тут такой выбор не предоставляется, поэтому, чтобы форсировать группы на 19-20ю, мы выберем ECDHE.

 

    1. AES-128 надо предпочесть AES-256 в исключительно редком варианте, когда криптографические вычисления (в силу огромного потока трафика) нагружают CPU так, что это является критичным. Хотя в таком случае лучше подумать о более серьёзном процессоре, ну или балансировке нагрузки, но тут как получится уж – а мы пока остановимся на логике “если уж поддерживается AES, то AES-256”.

 

    1. Выбор хэша из SHA-2 (SHA-256 или SHA-384 или SHA-512) – по сути, меньше всего влияющее на безопасность трафика дело, т.к. что на SHA-256, что на более старшие хэши, атаки именно на фальсификацию “на лету” пока особо не придумано. Нам важнее, чтобы быть более защищённым в ситуации “кто-то полностью заснифил сессию и в оффлайне хочет расшифровать её содержимое”, а тут хэш особо не интересен. Поэтому я бы предложил остановиться на SHA-256, исключительно по причине сомнительности траты ресурсов на данную задачу.

 

  1. AES-GCM лучше, чем AES-CBC, но он бывает только в TLS 1.2, исключительно. Поэтому оставлять его как единственный вариант – правильно лишь при абсолютной уверенности, что все хосты, взаимодействующие по TLS, поддерживают 1.2 со всеми “новшествами”.

Переберём список в соответствии с этой логикой и получим следующий вариант:

Всё с TLS_ECDHE_ECDSA_* , с AES-256, в порядке убывания стойкости хэшей/EC-групп

Всё с TLS_ECDHE_RSA_* , с AES-256, в порядке убывания стойкости хэшей/EC-групп

Если есть одинаковые варианты, различающиеся только по AES, то вариант с AES-GCM выше.

Плюс, понятное дело, обязательный минимальный для TLS 1.2 вариант TLS_RSA_WITH_AES_128_CBC_SHA (если надо TLS 1.0, то ещё и TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA). Их наличие, конечно, не очень хорошо, но согласование пойдёт со “старших” cipher suites, поэтому данная ситуация будет все равно гораздо лучше, чем дефолтная.

Действуем – если используете ATcmd, то можете править коммандами add, clean и видеть результаты сразу, на ходу. Если нужно задать в масштабах домена – неплохо будет сделать отдельную политику типа “Hisec TLS” – надо будет зайти в настройку групповых политик, выбрать там Computer Configuration -> Administrative Templates -> Network -> SSL Configuration Settings -> SSL Cipher Suite Order и указать нужные cipher suites – как положено по инструкции, через запятую и без пробелов, начиная с самых стойких. Строка ограничена 1023 символами, но нам их, после секвестра списка, вполне хватит.

Список можно подсократить, исходя из логики “используется только современный браузер, все субварианты указывать нет смысла, если поддерживает SHA-2, то там и SHA-256, и SHA-384 сразу точно есть”. В итоге он может выглядеть, допустим, так:

TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521,
TLS_RSA_WITH_AES_128_CBC_SHA

Далее – жестко убираем даже малейшую возможность использования слабых криптоалгоритмов.

Блокируем небезопасные криптоалгоритмы

В Windows поддерживается множества криптоалгоритмов, которые на данный момент уже совсем не нужны. Например, есть поддержка хэшей MD2 и MD4 – они использовались в ранних реализациях стека IPsec (который для Windows 2000 разрабатывала компания Cisco, поэтому он с первой же версии работал, а не как иногда бывает), а сейчас встречаются разве что в древних сертификатах Verisign. Или классический DES, который в силу роста вычислительных мощностей, да и того, что в ключе из 64 бит только 56 являются уникальными, уже не безопасен, т.к. его bruteforce доступен коммерческим заказчикам. Или замечательные по стойкости шифры RC2 на 40 и 56 бит, или RC4 (который уже вполне официально, с февраля 2015 года, в TLS поддерживать не надо – см. RFC 7465).

В общем, мы в явном виде “убьём” в системе следующие криптоалгоритмы: NULL, RC2, RC4, DES, 3DES, MD2, MD4. На всякий случай, так сказать.
Отключаем небезопасные криптоалгоритмы в Windows Server

Настраиваем фрагментацию TLS

При обмене TLS передаёт данные сообщениями (message). Максимальный размер данных сообщений ограничен в TLS 1.0 – и равен 16.384 байт. Если какое-либо сообщение (не данные, а всё, включая заголовки) больше этого числа, то включается механизм фрагментации TLS (не путайте с IP-фрагментацией). Данный механизм изначально поддерживается в NT 6.1 (Windows 7 и Windows Server 2008 R2) – для остальных систем нужен патч KB 2541763.

Проблема в том, что у разных серверов данное значение может быть разным – да и у клиентов (особенно мобильных) – тоже. На практике встречаются значения от 8192 байт (половинный стандарт, такое было на WinMobile) до 32768 байт (некоторые web-сервера). Поэтому нам нужно заранее подготовиться к этому, разрешив обработку фрагментов крупного размера. Это повлияет на многое – простейший пример; сервер считает, что максимальный размер фрагмента – 32К, и отдаёт в процессе TLS-handshake’а пачку сертификатов (он же имеет право ознакомить клиента с цепочкой оных, чтобы упростить ему проверку подлинности предъявляемого своего серверного сертификата), которая в сумме весит 20К. А клиент принимает только до 16К. Результат – отбой сессии на фазе установления.

Что мы можем настроить? Три значения – максимальный размер TLS-фрагмента, который мы отправляем, если мы:

    • TLS-клиент (параметр client)

 

    • TLS-сервер для клиента, который не аутентифицировался при помощи предъявления x.509 – сертификата (параметр server)

 

  • TLS-сервер для клиента, который аутентифицировался при помощи предъявления x.509 – сертификата (параметр serverauth)

Делается это несложно:

Настройка TLS-фрагментации

Замечу также, что данные значения имеют максимумы (соответственно, в порядке указания, 32К, 16К, 32К – т.е. фрагменты максимально могут быть до 32К, за исключением случая подключения неаутентифицирующегося клиента) и связаны следующей логикой – для определения максимального размера фрагмента в последнем из сценариев (подключение клиента, подтверждающего свою подлинность сертификатом) берётся максимальное значение из пары server / serverauth.

Установим всё в максимальные значения, чтобы принимать все возможные фрагменты, и продолжим.

Анти-BEAST или принудительная TLS-фрагментация

В 2012 году для обработки специфичной атаки (тот самый BEAST) фирма Microsoft выпустила специальный патч, который добавлял дополнительное управление фрагментацией (уже не размером фрагмента, а самой логикой работы оной) в SCHANNEL. В принципе, атака BEAST отражается просто – надо не использовать TLS 1.0 и SSL 3.0, а использовать только TLS 1.1 и выше, но это легко сказать, но трудно реализовать в современном интернете, где куча опенсорсных поделок годами работают с устаревшими и уязвимыми реализациями протоколов и стандартов, исходя из отговорок вида “раз вообще хоть кое-как работает, то работает идеально, это же СПО”. Поэтому да, если бы все системы, подключающиеся по TLS, были бы хотя бы Windows 7 или Windows Server 2008 R2, можно было бы просто включить только TLS 1.2 и автоматически решить огромное число проблем – но увы, приходится делать это иначе.

После установки данного патча (это KB 2638806 или, если сразу для всех платформ и подробнее – MS12-006 / CVE-2011-3389) у нас появляется возможность выбрать из нескольких вариантов. Первый и используемый по-умолчанию вариант – это “В случае, если другая сторона подтверждает отправкой флага при установке SSL/TLS-сессии, что тоже установила этот патч и настроена его использовать, фрагментировать handshake так, чтобы избежать использования атаки BEAST на блочные шифры”. Т.е. говоря проще, если данный патч везде установлен, всё происходит само. Два других варианта – это принудительно фрагментировать handshake всегда или никогда.

Мы бы, конечно, выставили “всегда”, но всё же это повлечёт много проблем с совместимостью, да и не забываем, что все эти пляски интересны только если у нас исключительно TLS 1.0, на старших версиях этой проблемы уже нет. Поэтому выставим в явном виде дефолтный режим:

Выставляем TLS SendExtraRecord в opt in

Теперь далее.

SSL Close-Notify

Когда клиент закрывает TLS-сессию, есть два варианта поведения со стороны сервера – полноценно закрыть её и сэкономить силы, “прикрыв на время”, чтобы в случае переподключения того же клиента продолжить работу с ним, не выполняя “с нуля” всю криптографическую и математически интенсивную работу – генерацию ключевого материала и подобное. Это поведение можно настроить, влияя на параметр SSL Close-Notify.

По умолчанию включён “облегчённый” режим – мы включим полновесный, так как это закроет целый класс атак на truncation – игры с манипуляцией длинами ответов и запросов.

Обработка Close-Notify в TLS

Обращу внимание, что включение этого режима, по сути, обозначает так же и то, что мы, как сервер, будем не только обрабатывать клиентский Close-Notify, но и будем отправлять клиенту явное уведомление о том, что закрываем сессию и новая будет создаваться “с нуля”.

Журналирование TLS

Подсистема SCHANNEL, которая отвечает в ОС на базе Windows за встроенную реализацию TLS, может сообщать о своих ошибках и проблемах в отдельный журнал. Для отслеживания результатов наших настроек, да и вообще, чтобы не пропустить критичные ошибки, настроим это журналирование:

Настройка журналирования TLS

Обратите внимание – анализ ошибок SCHANNEL – очень хороший способ “вычищения” потенциальных неприятностей до того, как они станут реально мешать работе. Во многих случаях SCHANNEL не может согласовать что-то, молча переходит на упрощённый/ослабленный режим и работает дальше, а администратор про это просто не знает, предполагая, что раз ОС новая и все патчи установлены, то защищённость высокая. Журналирование SCHANNEL поможет наглядно увидеть, всё ли так хорошо, как кажется. 🙂

Отправка клиенту списка доверенных CA в CTL-формате

Когда клиент подключается к серверу, тот может предоставить ему список тех issuers, кому сервер доверяет. Это и логично – в случае, если клиент имеет широкие возможности по аутентификации при помощи x.509-сертификатов, данный список поможет автоматически уменьшить список потенциально пригодных для подтверждения своей подлинности сертификатов.

Однако, начиная с NT 6.2, данная практика считается небезопасной и отправка этого списка отключена по-умолчанию. Это, кстати, ещё и ускоряет установление соединения.

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

Отключение отправки списка issuer CA в виде CTL клиенту

Логика проверки x.509-сертификата клиента

Обычно этот момент не очень акцентируется в логике установки SSL/TLS-соединения – подразумевается что-то типа “ну, клиент должен предоставить нормальный такой сертификат”, не уточняя, что точно имеется в виду под этим. Давайте разберёмся.

Понятно, что сертификат клиента должен быть валидным на базовом уровне – т.е. правильного формата, не просроченный, не потерявший целостность, обладающий всеми обязательными полями. Но в остальном критерии “подходящий” могут быть разными. Мы можем влиять на логику проверки, выбирая один из трёх вариантов:

  • Проверка цепочки доверия сертификата клиента считается удачной, если цепочка закончилась на сертификате, входящем в Trusted Issuers (например, IIS-серверу предоставили CTL-файл с ними в явном виде) (это параметр machinetrust)
  • Проверка цепочки доверия сертификата клиента считается удачной, если цепочка закончилась на сертификате, входящем в Trusted Issuers и являющимся корневым (т.е. самоподписанным) (это параметр exclusiveroot)
  • Проверка цепочки доверия сертификата клиента считается удачной, если цепочка закончилась на сертификате, входящем или в Trusted Issuers, или в локальное хранилище сертификатов (это параметр exclusiveca)

Что выбрать в конкретном варианте – нужно смотреть для каждой ситуации отдельно, но например вариант exclusiveroot будет увеличивать время процессинга, игнорируя то, что сертификат клиента уже признан валидным, т.к. подписан валидным intermediate CA, но будет добавлять безопасности, т.к. валидация intermediate CA, по сути, будет постоянной и принудительной.

Вы сможете повлиять на это командой clienttrust в контексте tls:

Логика проверки сертификата клиента

Не забудьте, что этот параметр влияет только на ситуации, когда клиент подтверждает свою подлинность сертификатом. И это необязательно лобовой сценарий “Кто-то с токеном удалённо подключается к корпоративному порталу” – это, например, 802.1x в случае, когда машинам раздали сертификаты. Это wifi, когда клиенты с сертификатами и EAP-TLS / PEAP. Будьте осторожны с тюнингом таких параметров, и первоначально точно выясните, на что это повлияет на данном конкретном сервере.

Проверка промежуточных сертификатов через Интернет

Когда клиент предъявляет свой сертификат, мы проверяем всю цепочку доверия, пока не натолкнёмся или на ошибку, или на явно доверенный сертификат. Однако, не все родительские сертификаты могут быть у нас (сервера) локально – возможно, что проверка цепочки клиента повлечёт за собой необходимость загрузить сертификат (или несколько) по указанному URL’у.

Это действие не всегда нужно или полезно – например, публичному серверу при такой логике работы можно сделать интересную проблему, заставляя его пачками пытаться загружать сертификаты с удалённого и медленного сервера, создавая множественные “потихоньку открывающиеся” SSL/TLS-соединения. В ряде же ситуаций – допустим, когда к серверу должны подключаться только свои, корпоративные клиенты, предъявляя свои, местные сертификаты, вопрос о том, надо ли серверу обращаться в Интернет, чтобы узнать про их подлинность, вообще исключается.

Мы сделаем настройку как раз под такой сценарий – выключим возможность подгрузки intermediate CA certificates из Интернета.

Загружаем сертификаты промежуточных CA только из локального хранилища

Теперь про дополнительный механизм безопасности HTTPS, включаемый на уровне веб-сервера.

Механизм HSTS – HTTP Strict Transport Security

Данный механизм, по своей сути, преследует достаточно простую цель – сделать так, чтобы ресурс, доступный по HTTPS, был бы доступен исключительно по HTTPS, без возможности “сваливания” в обычный HTTP. Т.е. если у вас есть сайт вида https://mail.atraining.ru/owa , то предполагается, что всё взаимодействие клиента идёт только по HTTPS, даже если каким-то образом клиенту будет подсунута ссылка на http-версию (обычно в целях перехвата данных).

Реализуется это с двух сторон, сервером и клиентом. Сервер:

  • Добавляет в HTTP-ответ специальный заголовок, в котором говорит, что надо включить данный механизм.
  • Указывает в параметрах время, которое будет действовать данная директива (т.е. что-то вида “вот с текущего момента и ещё целый год, ты сюда ходи только по https, если увидишь ссылку на этот домен, но с http – поправь доотправки запроса”)

Клиент:

  • Поддерживает в браузере анализ этого заголовка и следование указаниям со стороны сервера.
  • Если видит проблему с подключением – например, недоверенный сертификат – сразу отказывается устанавливать соединение (т.е. действует жестче, чем обычно).

Звучит достаточно просто – но по факту, данный механизм отсекает целую пачку потенциальных проблем вида “после установки HTTPS-сессии как-то удалось перейти обратно на HTTP”, например атаку SSL-stripping MItM (делается утилитой sslstrip), или кражу cookies через утилиту Firesheep.

Проблемой HSTS будет то, что самое первое обращение к серверу будет не знать про этот механизм, ну и то, что злонамеренные товарищи могут “срезать” этот доп.заголовок в ответе. Но – никто и не говорит, что это 100%е решение, таких решений вообще в природе нет. Частично вопрос проблемы первичного обращения снимается заданием pre-loaded списков сайтов в некоторых новых браузерах, частично – фактическим отключением HTTP для защищаемых ресурсов (весьма хороший метод). Главное, что любая атака, подразумевающая “downgrade” уже установленной HTTPS-сессии натолкнётся на то, что при включённом и согласованном HSTS браузер сам “на лету” исправит HTTP-ссылки на HTTPS и продолжит работу.

Как включать? Зайдём в консоль управления IIS и выберем там HTTP Response Headers для нужного нам сайта:

Настраиваем HTTP Strict Transport Security для IIS

Задаём заголовок HSTS и указываем ему два параметра:

Включаем HTTP Strict Transport Security для IIS

Первый – max-age – указывает, сколько времени в секундах, после получения распознанного ответа от сервера с данным заголовком, получателю (user agent’у, в нашем случае – браузеру) надо относить сервер к категории Known HSTS hosts и работать с ним в соответствии с этим. Второй – includeSubDomains – будет указывать, что в случае, если внутри HTTPS-сессии будет получена ссылка на ресурс, находящийся на субдомене относительно текущего (т.е. идёт работа с example.com, и в ответе приходит ссылка на CSS-файл с ресурса cdn.example.com), необходимо действовать в той же логике, т.е. предотвращать уход на HTTP.

Результат глазами увидеть будет трудно, но различные средства анализа защищённости увидят, что сервер поддерживает HSTS:

Результат - работающая HSTS

Данная технология поддерживается всеми современными браузерами – за исключением, увы, IE – только его 11я версия, притом работающая на Windows 10 Tech Preview, читает данный заголовок и следует вышеуказанной логике. Ну, будем надеяться, что это скоро поправят – добавление этого функционала не кажется каким-то сверхсложным.

Да, если что – данный механизм детально описан в RFC 6797, но в общем-то про весь его функционал мы уже рассказали.

Теперь посмотрим про кэширование – им тоже нужно управлять, чтобы, например, защититься от избыточной нагрузки в случае часто переподключающихся клиентов.

Кэшируем SSL/TLS-сессии – используя Session ID

Задача кэширования SSL/TLS достаточно древняя. Очевидно, что криптографические операции по совместной генерации ключевого материала и обмена оным – достаточно серьёзно напрягают процессор. Очевидно, что во всей задаче установки и поддержания работы SSL/TLS-сессии таких задач много, и разных – некоторые из них могут достаточно легко быть ускорены оборудованием (допустим, шифрование AES), а некоторые всё же придётся делать программно.

Поэтому есть смысл как-то упростить жизнь клиента, который – в силу обрыва связи, или какой-то ещё причины – повторно подключается к серверу. Как-то сделать так, чтобы ему не надо было “с нуля” инициировать сессию. Самый простой вариант – это ввести некий идентификатор сессии, Session ID.

Реализовано это будет так – когда сервер будет отправлять SERVER HELLO, он будет добавлять туда случайно сгенеренный идентификатор сессии. Клиент, если поддерживает данный механизм, сохраняет этот идентификатор, и после может добавить его в CLIENT HELLO, когда будет устанавливать новую сессию. Сервер, как понятно, хранит информацию только успешно установленных сессий, и записывает доп.данные клиента – например, адрес, из-под которого клиент подключается. Если всё ОК, то сессия продолжается, и клиента подключат по сокращённому сценарию согласования – весь этот механизм описан подробно и пошагово в RFC 5246. Этот механизм поддерживается начиная с Windows Server 2003 – раньше его надо было дополнительно включать, а теперь он включен в SCHANNEL по умолчанию.

Что же будет кэшироваться? В кэше SCHANNEL будут находиться следующие элементы сессии:

  • Master secret – т.е. тот криптографический материал, ради которого был весь стартовый DH/ECDH обмен.
  • Список согласованных cipher suite’ов.
  • Загруженные сертификаты (в случае серверного кэша – сертификаты, которые предъявил клиент, в случае клиентского – серверные).

Как понятно, возможность не согласовывать/загружать перечисленное выше хорошо ускорит процесс переподключения. Поэтому механизм этот полезный, а нам остаётся только настроить его.

Для этого мы откроем ATcmd, зайдём в контекст tls cache и выставим там три параметра – максимальный размер кэша Session ID, и тайм-аут одиночных элементов.
Настройка TLS Session ID в Windows Server
Понятное дело, если ожидается ещё более масштабная нагрузка – параметр “размер кэша” можно увеличить, ну и поиграть со значениями тайм-аутов.

Кэшируем SSL/TLS-сессии – используя Session Tickets

Логика работы данной технологии будет совершенно иной, чем в предыдущем варианте. В случае включения со стороны сервера данного механизма, который полностью называется Transport Layer Security (TLS) Session Resumption without Server-Side State (см. RFC 5077), на сервере создаётся специальный мастер-ключ, которым шифруются комплекты элементов сессии – почти как в предыдущем варианте – но храниться они будут у клиентов, а не на сервере. Т.е. Session Tickets – это когда сервер шифрует неизвестным клиенту ключом данные о взаимно установленной сессии, и отдаёт клиенту на хранение, а после клиент предъявляет их, сервер успешно расшифровывает, и тогда может продолжать работу.

Звучит изящно, но проблема в том, что это снижает безопасность, т.к. ключ один, и в случае его компрометации будут потенциально уязвимы все Session Tickets, выданные за время действия ключа.

Я бы не рекомендовал включать эту технологию, т.к. плюсы в части производительности, если применяются остальные технологии оптимизации, невелики, а вот потенциальные проблемы – есть.

Если всё же захотите включить – это несложно.

Создайте в безопасном месте сервера папку, где будет хранится ключ. После – запустите командлет New-TlsSessionTicketKey, указав ему в качестве параметра путь хранения файла с ключом. Например так:

New-TlsSessionTicketKey -Path “C:\TLSKeys\mail-atraining-ru.config”

Командлет попросит Вас придумать пароль – задайте действительно сложный, знаков в 40-50, тем более, что вам этот пароль потребуется лишь пару раз. После успешного выполнения командлета, определите, под какой учётной записью работает Application Pool того сайта, которому вы хотите разрешить использовать эту технологию кэширования, и включите, опять указав пароль при выполнении командлета:

Enable-TlsSessionTicketKey -Path “C:\TLSKeys\mail-atraining-ru.config” -ServiceAccountName “gMSA81$”

В общем-то всё, теперь механизм работает – если захотите поменять ключ, то отключите командлетом Disable-TlsSessionTicketKey, а после создайте новый ключ и опять включите.

Пока всё.

Заключение

Настройка, защита и оптимизация TLS – это важный момент для обеспечения безопасности практически любой современной IT-системы, т.к. эти протоколы по сути лидируют в количество серверных продуктов, использующих их как защиту для передачи данных. Как видно, помимо “просто включить и не париться” есть много других моментов, нужных для эффективной работы. Надеюсь, что эта статья чем-то поможет.

Удачного применения знаний!