TLS по OWASP: внутренний чеклист после трёх лет тяжёлых атак
OWASP обновил TLS Cheat Sheet после BEAST, POODLE и Heartbleed. Составили внутренний чеклист и автоматизировали проверку через testssl.sh - разбираем что и почему.
OWASP обновляет рекомендации по настройке TLS после серии атак BEAST (2011), CRIME (2012), BREACH (2013), Heartbleed и POODLE (2014)
После POODLE в октябре мы в очередной раз прошлись по TLS-конфигурациям клиентских серверов. Итог оказался предсказуемым: не всё, что было «нормально» полгода назад, остаётся нормальным сегодня. OWASP к этому моменту обновил свой TLS Cheat Sheet, приведя его в соответствие с реальностью последних трёх лет. Мы взяли его за основу и собрали внутренний чеклист, по которому теперь проверяем серверы клиентов в рамках аудита безопасности.
Почему OWASP и почему сейчас
С 2011 по 2014 год вышла целая серия атак, которые планомерно дырявили TLS-стек. BEAST (2011) - атака на TLS 1.0 в CBC-режиме. CRIME (2012) и BREACH (2013) - атаки на сжатие TLS и HTTP. Heartbleed (апрель 2014) - утечка памяти через OpenSSL. POODLE (октябрь 2014) - финальный гвоздь в SSLv3. Каждый раз реакция примерно одна и та же: срочно патчим, отключаем, обновляем. Но системного взгляда на конфигурацию при этом не возникает.
OWASP TLS Cheat Sheet - хороший повод такой взгляд взять. Это не маркетинг и не «топ-5 советов». Это конкретный список того, что нужно проверить и почему. Мы адаптировали его под наш стек (nginx, Apache, Postfix) и добавили пункты, которые регулярно всплывали у клиентов.
Что вошло в чеклист
Протоколы. SSLv2 и SSLv3 - отключить безоговорочно. SSLv3 мы отключали в октябре после POODLE, SSLv2 должен быть давно мёртв, но на старых серверах иногда всплывает. TLS 1.0 - серая зона: атаки на него есть (BEAST), но и клиентская база, которая не умеет ничего новее, тоже есть. Наша позиция: TLS 1.0 отключаем там, где клиент подтвердил отсутствие зависимостей. TLS 1.1 и 1.2 - обязательны.
Шифры. RC4 - убрать. Несмотря на то что RC4 долго считался лечением от BEAST (fallback вместо CBC), атаки на сам RC4 накопились до уровня, где он стал хуже проблемы, которую «лечил». NULL-шифры, EXPORT-шифры, анонимный DH - убрать. Оставить: ECDHE и DHE с AES-GCM как приоритет, AES-CBC с SHA2 как запасной. Набор почти совпадает с тем, что мы прописывали в августе.
DH-параметры. 2048 бит минимум. Дефолтные 1024-битные параметры - в мусор. Генерация разовая, производительность не страдает.
HSTS. Strict-Transport-Security добавляем там, где HTTP-to-HTTPS переход выстроен надёжно. Директива max-age - не меньше шести месяцев. Включать без подготовки не стоит: если сертификат ляжет - сайт станет недоступен для браузеров, которые уже запомнили заголовок. Мы в августе специально не добавляли его по умолчанию - мнение не изменилось, но для серверов, где HTTPS единственный протокол и процедура обновления сертификатов отлажена, включаем.
OCSP Stapling. Включаем при наличии корректной цепочки сертификатов. Ускоряет TLS-рукопожатие и убирает замечание от ssllabs. Единственное условие - nginx должен уметь достучаться до OCSP-сервера CA. На серверах с жёсткими исходящими правилами проверяем отдельно.
Цепочка сертификатов. Промежуточные сертификаты должны передаваться в ssl_certificate. Браузеры в большинстве случаев достраивают цепочку сами, но это неявное поведение с зависимостями. ssllabs явно снижает оценку за неполную цепочку.
Сжатие TLS. Отключить. Nginx по умолчанию не сжимает на уровне TLS, Apache - может. Проверить и выключить: SSLCompression off.
Автоматизация через testssl.sh
Проверять всё это руками по каждому серверу - занятие для мазохистов. У нас уже был опыт с ssllabs для разовых проверок, но ssllabs публичный и кешируется, что неудобно при итеративной правке конфига. Для автоматизации взяли testssl.sh - bash-скрипт, который проверяет тот же набор параметров локально, без внешних запросов.
Сделали простой обёртку:
#!/bin/bash
# tls-check.sh - прогон testssl.sh по списку хостов
HOSTS_FILE="${1:-hosts.txt}"
REPORT_DIR="reports/$(date +%Y%m%d)"
mkdir -p "$REPORT_DIR"
while read host; do
[[ -z "$host" || "$host" == \#* ]] && continue
echo "==> $host"
./testssl.sh --quiet --color 0 \
--protocols --ciphers --headers --vulnerable \
"$host" > "$REPORT_DIR/${host//\//_}.txt" 2>&1
done < "$HOSTS_FILE"
echo "Готово. Отчёты в $REPORT_DIR/"
Запускаем после каждого изменения конфигурации и раз в квартал как плановая проверка. Флаги --vulnerable прогоняет проверки на известные атаки - Heartbleed, POODLE, BEAST, CRIME, BREACH. --headers проверяет HSTS и другие security-заголовки.
testssl.sh не требует установки зависимостей сверх стандартного OpenSSL и bash - это важно, потому что гонять сторонний трафик с клиентских серверов через публичный ssllabs не всегда приемлемо.
Что нашли в процессе
Пара наблюдений, которые вылезли при прогоне по клиентам.
RC4 как «включённый по умолчанию». На нескольких серверах RC4 был в наборе шифров, хотя никто его специально не добавлял - он шёл из дефолтного конфига дистрибутива или старой документации. Выясняется при первом же прогоне testssl.sh.
HSTS без HTTPS на всех поддоменах. Один клиент добавил HSTS с includeSubDomains на основной домен, не подумав, что несколько поддоменов у них работают только по HTTP. После включения HSTS они стали недоступны. Добавили в чеклист отдельный пункт: перед HSTS с includeSubDomains - инвентаризация поддоменов.
OCSP и файрвол. На двух серверах OCSP Stapling не работал из-за того, что файрвол резал исходящие TCP-соединения на нестандартные порты. nginx молча игнорировал ошибку - нужно смотреть в error.log. Добавили проверку в скрипт: openssl s_client -connect host:443 -status.
Текущий статус
Чеклист внутренний, в виде markdown-документа с чекбоксами - прогоняем его по каждому серверу при первичном аудите и при квартальном проходе. testssl.sh автоматизирует большую часть пунктов, оставляя человеческий взгляд для тех вещей, где контекст важен: IE6, поддомены с HTTP, серверы с нестандартными требованиями к совместимости.
2014 год показал, что TLS-конфигурация - это не «настроил один раз и забыл». Это живой объект, который требует ревью при каждом новом CVE. Чеклист помогает хотя бы не делать это с нуля каждый раз.
- SSL-аудит nginx после Heartbleed: от B до A минимальными правками · 19 августа 2014
- POODLE (CVE-2014-3566): SSLv3 отключаем везде, без исключений · 14 октября 2014