Padding oracle и ошибки режимов

Как один-единственный бит обратной связи — «паддинг правильный или нет» — позволяет расшифровать сообщение, не зная ключа.

Padding oracle — уязвимость, при которой система по-разному реагирует на корректный и некорректный паддинг расшифрованного блока, и эта реакция (ошибка, время ответа, код статуса) превращается в «оракула», помогающего восстановить открытый текст.

Это хрестоматийный пример того, как безупречный шифр (AES в режиме CBC) ломается из-за того, ЧТО система сообщает наружу. Сам ключ остаётся неизвестным — атакующему достаточно уметь спрашивать сервер «подходит ли паддинг?» и наблюдать ответ.

Зачем это знать защитнику

Padding oracle годами всплывал в реальных протоколах (атаки на TLS вроде POODLE и Lucky Thirteen — родственники этой идеи). Урок для защитника фундаментальный: шифрование само по себе не защищает целостность. Если приёмник расшифровывает любой присланный ему шифртекст и как-то реагирует на «мусор» внутри, он невольно становится оракулом. Понимание этого диктует выбор режима: только аутентифицированное шифрование (AEAD), которое отвергает подделанный шифртекст ещё до того, как что-либо о нём «расскажет».

Как режим CBC создаёт оракула

В CBC сообщение делится на блоки, и каждый блок перед шифрованием XOR-ится с предыдущим шифрблоком. Чтобы длина была кратна блоку, добавляют паддинг по схеме PKCS#7: дополняют байтами, значение которых равно их количеству (один недостающий байт — 01, три — 03 03 03). При расшифровке приёмник проверяет, что паддинг валиден.

Проблема в обратной связи. Если сервер на неверный паддинг отвечает «ошибка дешифрования», а на верный — «ошибка данных» (или просто отвечает с разной задержкой), он раскрывает один бит: «паддинг корректен?». Концептуально процесс выглядит так:

Атакующий подменяет байты предыдущего блока и шлёт серверу.
Сервер расшифровывает -> XOR с подменёнными байтами -> проверяет паддинг.
  если ответ "паддинг неверный"  -> гипотеза не подошла
  если ответ "паддинг верный"    -> найден байт промежуточного значения
Зная промежуточное значение и настоящий предыдущий блок,
атакующий вычисляет байт открытого текста — БЕЗ ключа.
Повторяя по байту, восстанавливает блок целиком.

Важно: это не «угадывание» сообщения, а детерминированное восстановление по одному биту обратной связи на каждый подобранный байт. Никаких подробностей подбора здесь не нужно — суть в том, что любая различимая реакция на структуру расшифрованного блока опасна.

Другие ошибки режимов

Padding oracle — частный случай большого класса «использовали шифрование без аутентификации». Сюда же:

  • ECB — шифрует одинаковые блоки одинаково, выдавая структуру данных (классическая демонстрация — «зашифрованная картинка пингвина», на которой всё ещё виден силуэт).
  • CBC/CTR без MAC — позволяют атакующему незаметно менять биты шифртекста, влияя на открытый текст предсказуемым образом.
  • MAC-then-Encrypt и «сначала расшифруй, потом проверь» — приёмник вынужден обрабатывать неаутентифицированные данные, открывая окно для оракулов.

Как это работает под капотом

Корень — нарушение принципа: получатель не должен совершать НИКАКИХ наблюдаемых действий над шифртекстом, пока не убедится в его подлинности. В уязвимой схеме порядок обратный: сначала расшифровали, потом (или вообще никогда) проверили целостность. Любой шаг между «расшифровал» и «проверил подлинность» — потенциальный канал утечки: исключение, лог, ветка кода, задержка. Правильная схема — encrypt-then-MAC: сначала проверяем MAC по шифртексту, и если он не сошёлся, немедленно отвергаем, ничего не расшифровывая.

Полезно сравнить три порядка операций и понять, почему безопасен только один. При Encrypt-and-MAC (MAC считается по открытому тексту параллельно) сам тег может утечь о содержимом, а проверка происходит поздно. При MAC-then-Encrypt (сначала MAC по открытому тексту, потом всё шифруется) приёмник вынужден сперва расшифровать, чтобы добраться до MAC, — именно это окно и эксплуатирует padding oracle. И только Encrypt-then-MAC позволяет проверить подлинность, не прикасаясь к открытому тексту: MAC берётся по готовому шифртексту, сверяется constant-time-сравнением, и при несовпадении запрос отвергается мгновенно и единообразно. AEAD-режимы реализуют по сути этот же безопасный порядок внутри одного примитива, поэтому собирать схему вручную почти никогда не нужно.

Как защититься

  • Используйте AEAD. Aутентифицированное шифрование с присоединёнными данными — AES-GCM, ChaCha20-Poly1305 — шифрует И проверяет целостность одним примитивом. Подделанный шифртекст отвергается единообразно, оракула не возникает.
  • Если только CBC — то encrypt-then-MAC. Считайте HMAC по шифртексту (и IV), проверяйте его constant-time-сравнением ДО расшифровки. Не сошёлся — отвергайте, не трогая содержимое.
  • Единый ответ на любую ошибку. Не различайте «неверный паддинг» и «неверные данные» ни текстом, ни кодом, ни временем ответа. Снаружи всё «невалидно».
  • Никогда не пишите шифрование вручную. Берите cryptography (Python, класс AESGCM), libsodium (crypto_secretbox), Tink. Они по умолчанию аутентифицируют.
  • Не используйте ECB. Никогда, ни для чего, кроме узких низкоуровневых построений внутри других режимов.

Правовое напоминание: проверять устойчивость к padding oracle можно только на своих сервисах или в разрешённой лаборатории (DVWA, juice-shop, локальная ВМ). Атака на чужой реальный сервис незаконна (УК РФ ст. 272).

Итоги

  • Шифрование без аутентификации не защищает целостность — этим и пользуется padding oracle.
  • Любая различимая реакция на корректность расшифрованного блока (ошибка, код, время) — оракул, раскрывающий открытый текст без ключа.
  • Правильный порядок — encrypt-then-MAC: проверяем подлинность шифртекста ДО расшифровки.
  • Лучшая защита — AEAD (AES-GCM, ChaCha20-Poly1305) из проверенной библиотеки; единый ответ на все ошибки; никакого ECB и самописного крипто.
Проверьте себя
1. Какую обратную связь использует атака padding oracle?
AПолный текст ошибки с ключом шифрования
BРазличимый ответ системы на вопрос «корректен ли паддинг расшифрованного блока?»
CВремя генерации ключа на сервере
DДлину открытого текста
2. Какой подход надёжнее всего устраняет padding oracle и подобные атаки на режимы?
AИспользовать AEAD (AES-GCM, ChaCha20-Poly1305), которое шифрует и аутентифицирует вместе
BПерейти с CBC на ECB
CУдлинить ключ до 256 бит
DВозвращать максимально подробное сообщение об ошибке паддинга