Кратко
- HTML-преобразователь мог читать за пределами своего буфера и добавлять к ответу фрагменты других запросов, нарушая ожидаемую изоляцию клиентов на общей периферии.
- Аварийные выключатели и исправление парсера остановили новые раскрытия, но уже закешированные страницы и потенциально скомпрометированные секреты потребовали отдельного восстановления, завершение которого нельзя вывести из самого патча.
Сайт-триггер и владелец данных — не одно лицо
17 февраля 2017 года Project Zero сообщил Cloudflare, что некоторые страницы содержат посторонние данные: cookie, токены аутентификации, тела POST и другие куски памяти процесса. Часть ответов уже попала в кеши поисковых систем.
Название Cloudbleed напоминает Heartbleed, однако здесь решающей была многопользовательская архитектура. Общий процесс преобразовывал страницы многих клиентов. Ошибочный HTML одного сайта мог открыть уязвимый путь, а соседние байты, попавшие в ответ, — относиться к запросу другого клиента.
Поэтому перечень доменов, запустивших ошибку, не является списком жертв. Клиенту не требовалось пользоваться проблемной функцией: достаточно было разделить не тот процесс в неудачный момент. Нарушено не только условие корректного разбора документа, а более строгая граница: работа одного арендатора никогда не читает и не отправляет память другого.
Новая буферизация разбудила старую ошибку указателя
Cloudflare обнаружил дефект в старом коде, сгенерированном Ragel и используемом тремя HTML-функциями: маскировкой адресов электронной почты, Server-Side Excludes и автоматическим переписыванием HTTPS. Из-за отсутствующей операции fhold указатель мог остаться в конце буфера. Вызывающий код принимал результат за допустимый диапазон и копировал дальше границы.
Частота выросла после внедрения парсера cf-html, изменившего буферизацию. Cloudflare разделил роли: ошибка находилась не в Ragel и не в самом cf-html. Новый компонент изменил условия для наследуемого кода и превратил скрытый дефект в частую утечку.
Такой риск не виден при проверке одного нового модуля. Ввод в эксплуатацию должен испытывать точные границы, сравнивать старое и новое поведение и анализировать сбои всех прежних потребителей, которых вновь активирует новый путь.
Последовательность отключения в точных часах
Первый рычаг находился у оператора периферии. Подробная шкала UTC фиксирует получение сведений об ошибке 18 февраля в 00:32, всемирное отключение маскировки электронной почты в 01:19, автоматического переписывания HTTPS в 04:24 и развёртывание по всему парку патча с выключателем cf-html в 07:22. У Server-Side Excludes не было собственного глобального выключателя, поэтому его пришлось создать и развернуть во время инцидента.
Аварийный выключатель — часть безопасности функции, а не удобство эксплуатации. Без него во время кризиса приходится писать код. С ним необязательное преобразование можно пожертвовать, не останавливая независимую работу прокси.
Cloudflare сообщил, что закрытые SSL-ключи клиентов не были доступны через этот путь, поскольку завершение TLS выполнялось в отдельном экземпляре NGINX. Но в памяти HTTP-процесса находились закрытый ключ для шифрования между машинами Cloudflare и несколько внутренних секретов аутентификации. Разделение защитило один особенно опасный класс, но не сделало доступный набор секретов пустым.
Позднейшая реализация на Rust усилила локальную границу: безопасный код не допускает обычного доступа за пределами памяти. Это устраняет класс ошибок вместо надежды найти каждый неверный указатель на ревью. Rust сам по себе не доказывает правильную авторизацию и не защищает небезопасные библиотеки.
Оценка не равна переписи
Первый отчёт назвал 13–18 февраля периодом максимального риска и оценил вероятность примерно в один потенциально раскрывающий запрос на 3,3 миллиона, около 0,00003 процента. Поздний расчёт дал 1 242 071 срабатывание с 22 сентября 2016 года по 18 февраля 2017 года: 605 037 до 13 февраля от менее чем 180 сайтов и 637 034 за последние пять дней от 6457 сайтов.
Подробные журналы составляли однопроцентную выборку и имелись лишь за 8–18 февраля. Более ранние подробности уже удалили; старый период моделировался по агрегатам и данным сбоев. В исследованных записях Cloudflare не обнаружил признаков злонамеренной эксплуатации. Это не доказывает, что эксплуатации никогда не было.
Срабатывания не равны уникальным пострадавшим. Общая частота не передаёт ценность конкретного токена. Отсутствие следа в выборке не закрывает исторический вопрос.
Патч не отзывает отправленные байты
Отключение функций остановило новые загрязнённые ответы, но не ранее доставленные копии. Cloudflare оценил, что поисковые роботы создали более половины срабатываний, организовал удаление более 80 тысяч уникальных кешированных страниц и нашёл в сторонних кешах данные, связанные со 150 клиентами.
Ни одна цифра не задаёт верхнюю границу. Не каждая удалённая страница обязательно содержала секрет; 150 найденных клиентов не означают всего 150; очистка кеша не доказывает отсутствия частных копий. У сдерживания и восстановления разные критерии окончания.
Исправление парсера подтверждает лишь прекращение новых утечек по известному пути в проверенных условиях. Владельцы кешей отдельно удаляют материал. Клиенты отзывают или заменяют сеансы, токены, ключи API и пароли во всех доверяющих системах. Доказательство завершения — отказ старому секрету, а не выпуск нового.
Минимальная общая граница и обратимые местные решения
Принцип Running-Code Primacy Хэна Лу требует наблюдаемого результата: работающая периферия не выдаёт чужую память, состояние функций проверяемо, старые секреты отвергаются, а остатки в кешах обрабатываются их реальными владельцами. Надпись «решено» не создаёт этих фактов.
Минимальная начальная спецификация коротка и абсолютна: ответ содержит только данные, разрешённые для этого ответа. Необязательные преобразования, выбор парсера, темп выпуска и отключение остаются локальными решениями. Их можно менять или отвергать, не ослабляя общую изоляцию и не навязывая всем клиентам одинаковый риск.
Cloudbleed не опроверг общую инфраструктуру. Он показал, что ей нужна жёсткая мембрана, а каждый необязательный путь через неё должен уметь исчезнуть раньше всей службы.
Источники
Обзор для участников
Подробный контекст профиля
Войдите с подходящим уровнем подписки, чтобы открыть полный обзор и примечания к источникам.
Только для Стратегического сообщества
Стратегическое сообщество
Открыто всем читателям. Вступите и войдите, чтобы открыть обзоры профилей.
Вступить в Стратегическое сообществоТолько для Альянса лидеров
Альянс лидеров
Для проверенных владельцев IP-активов и руководителей. Войдите, чтобы открыть обзоры Альянса.
Вступить в Альянс лидеров