Уязвимость HTTP/2 DDoS атака с быстрым сбросом (Rapid Reset) - CVE-2023-44487
При определенных условиях эту уязвимость можно использовать для выполнения атаки типа "отказ в обслуживании" в nginx или других продуктах, реализующих серверную часть спецификации HTTP/2. Чтобы защитить ваши системы от этой атаки, рекомендуется немедленно обновить конфигурацию NGINX или другого веб-сервера.
С чего все началось, ряд сервисов Google подверглись новой DDoS-атаке на основе HTTP/2, пик которой пришелся на август. Эти атаки были значительно масштабнее, чем любые ранее зарегистрированные атаки 7 уровня, при этом самая крупная атака превысила 398 миллионов запросов в секунду.
Хотя воздействие было минимальным, группа реагирования на DDoS-атаки Google рассмотрела их и добавила дополнительные средства защиты для дальнейшего снижения эффекта подобных атак
Проблема со сбросом потока HTTP/2
Основной целью разработки HTTP/2 была эффективность, и к сожалению, функции, которые делают HTTP/2 более эффективным для официальных клиентов, также могут использоваться для повышения эффективности DDoS-атак.
Мультиплексирование потоков HTTP/2
Давайте вспомним как работает HTTP/2, после установления соединения с сервером протокол HTTP/2 позволяет клиентам инициировать параллельные потоки для обмена данными. В отличие от предыдущих итераций протокола, если конечный пользователь решает уйти со страницы или остановить обмен данными по какой-либо другой причине, HTTP/2 предоставляет возможность отменить поток. Это делается путем отправки кадра RST_STREAM на сервер, что избавляет его от ненужного выполнения работы.
Уязвимость используется путем запуска и быстрой отмены большого количества потоков HTTP/2 через установленное соединение, тем самым обходя максимум одновременно запущенных потоков сервера. Это происходит потому, что входящие потоки сбрасываются быстрее, чем приходят последующие потоки, что позволяет клиенту перегружать сервер, даже не достигая настроенного порога.
HTTP/2 использует "потоки", двунаправленные абстракции, используемые для передачи различных сообщений или «кадров» между конечными точками. «Мультиплексирование потоков» — это основная функция HTTP/2, которая позволяет более эффективно использовать каждое TCP-соединение. Потоки мультиплексируются таким образом, что их можно отслеживать с обеих сторон соединения, используя только одно соединение уровня 4. Мультиплексирование потоков позволяет клиентам иметь несколько текущих запросов без управления несколькими отдельными соединениями.
Одним из основных ограничений при организации DoS-атаки 7 уровня - является количество одновременных транспортных соединений. Каждое соединение требует затрат, включая память операционной системы для записей сокетов и буферов, время процессора для подтверждения TLS, а также то, что для каждого соединения требуется уникальный четырехкортеж, IP-адрес и пара портов для каждой стороны соединения, что ограничивает количество одновременных соединений между двумя IP-адресами.
В HTTP/1.1 каждый запрос обрабатывается последовательно. Сервер прочитает запрос, обработает его, напишет ответ и только потом прочитает и обработает следующий запрос. На практике это означает, что частота запросов, которые могут быть отправлены по одному соединению, составляет один запрос за цикл туда и обратно, где туда и обратно включается задержка сети, время обработки прокси-сервера и время обработки серверного запроса. Хотя конвейерная обработка HTTP/1.1 доступна на некоторых клиентах и серверах для увеличения пропускной способности соединения, она не распространена среди официальных клиентов.
С помощью HTTP/2 клиент может открывать несколько одновременных потоков в одном TCP-соединении, причем каждый поток соответствует одному HTTP-запросу. Максимальное количество одновременных открытых потоков теоретически контролируется сервером, но на практике клиенты могут открывать 100 потоков на один запрос, и серверы обрабатывают эти запросы параллельно. Важно отметить, что лимиты сервера не могут быть изменены в одностороннем порядке.
Например, клиент может открыть 100 потоков и отправить запрос по каждому из них за один проход; прокси-сервер будет читать и обрабатывать каждый поток последовательно, но запросы к внутренним серверам снова можно распараллелить. Затем клиент может открывать новые потоки по мере получения ответов на предыдущие. Это обеспечивает эффективную пропускную способность для одного соединения, равную 100 запросам за один проход, с константами времени прохождения туда и обратно, аналогичными запросам HTTP/1.1. Обычно это приводит к почти 100-кратному увеличению использования каждого соединения.
HTTP/2 Атака Rapid Reset
Протокол HTTP/2 позволяет клиентам указывать, что серверу следует отменить предыдущий поток, отправив фрейм RST_STREAM. Протокол не требует от клиента и сервера каким-либо образом согласовывать отмену, клиент может сделать это в одностороннем порядке. Клиент также может предположить, что отмена вступит в силу немедленно, когда сервер получит фрейм RST_STREAM, прежде чем будут обработаны любые другие данные из этого TCP-соединения.
Эта атака называется Rapid Reset, (быстрый сброс) поскольку она основана на способности конечной точки отправить фрейм RST_STREAM сразу после отправки фрейма запроса, что заставляет другую конечную точку начать работу, а затем быстро сбрасывать запрос. Запрос отменяется, но соединение HTTP/2 остается открытым.
Шаблон запроса и ответа HTTP/1.1 и HTTP/2
HTTP/2 Атака Rapid Reset, построенная на этой возможности, проста: клиент открывает большое количество потоков одновременно, как и в стандартной атаке HTTP/2, но вместо того, чтобы ждать ответа на каждый поток запросов от сервера или прокси, клиент немедленно отменяет каждый запрос.
Возможность немедленного сброса потоков позволяет каждому соединению иметь неопределенное количество запросов в процессе. Явно отменяя запросы, злоумышленник никогда не превышает ограничение на количество одновременных открытых потоков. Количество текущих запросов больше не зависит от времени приема-передачи (RTT), а только от доступной пропускной способности сети.
В типичной реализации HTTP/2 серверу по-прежнему придется выполнять значительный объем работы для отмененных запросов, например выделять новые структуры данных потока, анализировать запрос и выполнять распаковку заголовка, а также сопоставлять URL-адрес с ресурсом. Для реализаций обратного прокси-сервера запрос может быть передан на внутренний сервер до обработки фрейма RST_STREAM. С другой стороны, клиент практически ничего "не платит" за отправку запросов. Это создает полезную асимметрию затрат между сервером и клиентом.
Еще одно преимущество, которое получает злоумышленник, заключается в том, что явная отмена запросов сразу после создания означает, что обратный прокси-сервер не будет отправлять ответ ни на один из запросов. Отмена запросов до записи ответа уменьшает пропускную способность нисходящей линии связи (сервер/прокси-сервер для злоумышленника).
Варианты атаки HTTP/2 Rapid Reset
В течение нескольких недель после первых DDoS-атак было замечено несколько вариантов атак Rapid Reset. Эти варианты, как правило, не так эффективны, как первоначальная версия, но все же могут быть более эффективными, чем стандартные DDoS-атаки HTTP/2.
Первый вариант не отменяет потоки сразу, а вместо этого открывает сразу пакет потоков, ждет некоторое время, затем отменяет эти потоки и затем сразу открывает еще один большой пакет новых потоков. Эта атака может обойти средства защиты, основанные только на скорости входящих фреймов RST_STREAM (например, разрешать не более 100 RST_STREAM в секунду для соединения перед его закрытием).
Эти атаки теряют главное преимущество отменяющих атак, поскольку не позволяют максимизировать использование соединения, но все же имеют некоторую эффективность реализации по сравнению со стандартными DDoS-атаками HTTP/2. Но этот вариант действительно означает, что любое снижения последствий, основанное на отмене потока с ограничением скорости, должно устанавливать довольно строгие ограничения, чтобы быть эффективными.
Второй вариант полностью отказывается от отмены потоков и вместо этого оптимистично пытается открыть больше одновременных потоков, чем заявлено сервером. Преимущество этого подхода по сравнению со стандартной DDoS-атакой HTTP/2 заключается в том, что клиент может постоянно поддерживать конвейер запросов полным и исключить RTT клиент-прокси как узкое место. Это также может устранить RTT прокси-сервера как узкое место, если запрос адресован ресурсу, на который сервер HTTP/2 отвечает немедленно.
RFC 9113, текущий HTTP/2 RFC, предполагает, что попытка открыть слишком много потоков должна аннулировать только те потоки, которые превысили лимит, а не все соединение. Большинство серверов HTTP/2 не будут обрабатывать эти потоки, и именно это позволяет использовать вариант атаки без отмены, почти сразу принимая и обрабатывая новый поток после ответа на предыдущий поток.
Многогранный подход к снижению последствий
Конечно никто не ждет, что простая блокировка отдельных запросов станет эффективной защитой от атак этого класса - вместо этого при обнаружении злоупотреблений необходимо закрыть все TCP-соединение. HTTP/2 обеспечивает встроенную поддержку закрытия соединений с использованием типа фрейма для GOAWAY. RFC определяет процесс корректного закрытия соединения, который включает в себя сначала отправку информационного сообщения GOAWAY, не устанавливающего ограничения на открытие новых потоков, а затем отправку туда и обратно другого сообщения, запрещающего открытие дополнительных потоков.
Однако этот изящный процесс GOAWAY обычно не реализуется таким образом, чтобы обеспечить защиту от вредоносных клиентов. Эта форма смягчения делает соединение уязвимым для атак быстрого сброса на слишком долгое время, и ее не следует использовать для создания средств снижения последствий, поскольку она не останавливает входящие запросы. Вместо этого следует настроить GOAWAY для немедленного ограничения создания потока.
Это оставляет вопрос о том, какие связи являются злоупотребляющими. Отмена запросов клиента по своей сути не является злоупотреблением: эта функция существует в протоколе HTTP/2, чтобы помочь лучше управлять обработкой запросов. Типичными ситуациями являются ситуации, когда браузеру больше не нужен запрошенный им ресурс из-за того, что пользователь ушел со страницы, или приложения используют метод длительного опроса с тайм-аутом на стороне клиента.
Меры по смягчению последствий этого вектора атаки могут принимать различные формы, но в основном они сосредоточены на отслеживании статистики соединений и использовании различных сигналов и бизнес-логики для определения того, насколько полезно каждое соединение. Например, если соединение имеет более 100 запросов, причем более 50 % из них отменены, это может быть кандидатом на меры по снижению риска. Масштаб и тип ответа зависят от риска для каждой платформы, но ответы могут варьироваться от принудительных фреймов GOAWAY, как обсуждалось ранее, до немедленного закрытия TCP-соединения.
Чтобы защититься от варианта этой атаки без отмены, рекомендуется серверам HTTP/2 закрывать соединения, превышающие лимит одновременного потока. Это может произойти либо сразу, либо после небольшого количества повторных правонарушений.
Применимость к другим протоколам
Эти методы атаки не относятся напрямую к тому же HTTP/3 (QUIC) из-за различий в протоколах, и Google в настоящее время не видит, чтобы HTTP/3 использовался в качестве вектора DDoS-атаки в большом масштабе. Несмотря на это, рекомендуется реализациям серверов HTTP/3 заранее внедрять механизмы ограничения объема работы, выполняемой одним транспортным соединением, аналогично средствам снижения риска HTTP/2, обсуждавшимся выше.
В начале реагирования на эти DDoS-атаки и в координации с отраслевыми партнерами стало очевидно, что этот новый тип атаки может оказать широкое влияние на любую организацию, предлагающую протокол HTTP/2 для своих услуг.
В процессе раскрытия информации команда сосредоточилась на уведомлении крупных разработчиков HTTP/2, включая инфраструктурные компании и поставщиков серверного программного обеспечения. Целью этих предварительных уведомлений была разработка и подготовка мер по смягчению последствий для скоординированного выпуска. В прошлом этот подход позволял включать широко распространенные средства защиты для поставщиков услуг или делать их доступными через обновления программного обеспечения для многих пакетов и решений.
CVE-2023-44487
Google возглавил скоординированный процесс раскрытия уязвимостей и зарезервировал CVE-2023-44487 для отслеживания потенциальных исправлений реализаций HTTP/2.
Влияние на NGINX
Из соображений производительности и потребления ресурсов NGINX ограничивает количество одновременных потоков значением по умолчанию, равным 128 (см. http2_max_concurrent_streams ). Кроме того, чтобы оптимально сбалансировать производительность сети и сервера, NGINX позволяет клиенту сохранять HTTP-соединения для до 1000 запросов по умолчанию, используя HTTP-поддержку активности (см. keepalive_requests ).
Опираясь на лимит активности по умолчанию, NGINX предотвращает атаки такого типа. Создание дополнительных подключений для обхода этого ограничения выявляет злоумышленников с помощью стандартных инструментов мониторинга и оповещения уровня 4.
Однако если NGINX настроен с параметром поддержки активности, который значительно превышает значение по умолчанию и рекомендуемое значение, атака может истощить системные ресурсы. Когда происходит сброс потока, протокол HTTP/2 требует, чтобы никакие последующие данные не возвращались клиенту в этом потоке. Обычно сброс приводит к незначительной нагрузке на сервер в виде задач, которые корректно обрабатывают отмену. Однако обход порога потока NGINX позволяет клиенту воспользоваться этими издержками и усилить их, быстро инициируя тысячи потоков. Это приводит к резкому увеличению нагрузки на процессор сервера, отказывая в обслуживании законным клиентам.
Отказ в обслуживании путем установления потоков HTTP/2 с последующей отменой потока при аномально высоких ограничениях активности.
Шаги по снижению риска атак
Будучи полнофункциональным сервером и прокси-сервером, NGINX предоставляет администраторам мощные инструменты для предотвращения атак типа «отказ в обслуживании». Чтобы воспользоваться этими функциями, важно внести следующие обновления в файлы конфигурации NGINX, чтобы минимизировать поверхность атаки сервера:
Для параметра keepalive_requests следует оставить значение по умолчанию - 1000 запросов.
Для http2_max_concurrent_streams следует оставить значение по умолчанию - 128 потоков.
Также рекомендуется добавить следующие меры безопасности в качестве передовой практики:
limit_conn устанавливает ограничение на количество разрешенных подключений от одного клиента. Эту директиву следует добавить с разумной настройкой, обеспечивающей баланс между производительностью и безопасностью приложения.
limit_req устанавливает ограничение на количество запросов, которые будут обработаны в течение заданного периода времени от одного клиента. Эту директиву следует добавить с разумной настройкой, обеспечивающей баланс между производительностью и безопасностью приложения.
Чтобы обеспечить раннее обнаружение флуд-атак команда NGINX выпустила патч, для модуля ngx_http_v2_module, накладывающий ограничение на количество новых потоков, которые могут быть введены в один цикл событий. Этот предел устанавливается в два раза больше значения, настроенного с помощью директивы http2_max_concurrent_streams. Ограничение будет применено, даже если максимальный порог никогда не будет достигнут, например, когда потоки сбрасываются сразу после отправки запроса (как в случае с этой атакой).
Так же можно еще почитать дополнительную информацию о CVE-2023-44487 атаке с быстрым сбросом HTTP/2 https://www.cve.org/CVERecord?id=CVE-2023-44487 .
Что думаешь?