Хабрахабр

[Перевод] Технические детали недавнего сбоя расширений Firefox

Об авторе. Эрик Рескорла — технический директор группы Firefox в Mozilla

Это связано с ошибкой с нашей стороны: мы не заметили, что истёк срок действия одного из сертификатов, который используется для подписи дополнений, что привело к отключению подавляющего большинства из них. Недавно в Firefox произошёл инцидент, когда большинство дополнений (расширений, аддонов) перестали работать. Теперь, когда мы исправили проблему, и большинство дополнений восстановлены, я хотел бы подробно рассказать, что произошло, почему и как мы всё починили.

Для справки: расширения и их подпись

Хотя многие используют Firefox как есть из коробки, браузер также поддерживает мощный механизм расширений. Они добавляют в Firefox сторонние функции, расширяющие возможности, которые мы предлагаем по умолчанию. В настоящее время существует более 15 000 дополнений Firefox: от блокировки рекламы до управления сотнями вкладок.
Firefox требует, чтобы все установленные дополнения были подписаны цифровой подписью. Это требование предназначено для защиты пользователей от вредоносных расширений, требуя минимального стандарта проверки сотрудниками Mozilla. До того, как мы ввели это требование в 2015 году, у нас были серьёзные проблемы с вредоносными расширениями.

Он хранится в автономном режиме в аппаратном модуле безопасности (HSM). Подпись работает через предустановленный «корневой сертификат» Firefox. Когда расширение представлено для подписи, мы генерируем новый временный «сертификат конечного объекта» (end-entity certificate) и подписываем его с помощью промежуточного сертификата. Каждые несколько лет он используется для подписания нового «промежуточного сертификата», который хранится в онлайне и используется в процессе подписания. Визуально это выглядит следующим образом: Затем сертификат конечного объекта используется для подписи расширения.

В случае корневого сертификата это одно и то же, но для других сертификатов эмитентом является субъект, который его подписал. Обратите внимание, что у каждого сертификата есть «субъект» (которому принадлежит сертификат) и «эмитент» (подписавший).

Именно здесь возникла проблема: у каждого сертификата есть фиксированный срок действия. Важным моментом здесь является то, что каждое дополнение подписывается собственным сертификатом конечного объекта, но почти у всех аддонов один и тот же промежуточный сертификат (несколько очень старых дополнений были подписаны другим промежуточным звеном). К сожалению, промежуточный сертификат, который мы использовали, истёк 4 мая после 1:00 UTC, и сразу же каждое дополнение, которое подписано этим сертификатом, стало непроверяемым и не могло быть загружено в Firefox. До или после этого окна сертификат не будет принят, и расширение, подписанное этим сертификатом, не может быть загружено в Firefox.

Причина в том, что Firefox не постоянно проверяет дополнения на валидность. Хотя срок действия всех дополнений истёк около часа ночи, последствия ощутились не сразу. В результате, некоторые люди испытали проблемы сразу, некоторые — гораздо позже. Они проверяются примерно каждые 24 часа, причём время проверки отличается для каждого пользователя. Мы в Mozilla впервые узнали о проблеме около 18:00 PST в пятницу 3 мая и сразу собрали команду, чтобы исправить ситуацию.

Ограничение ущерба

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

В тот момент это было разумно, потому что подпись ставил недействительный сертификат. Во-первых, мы отключили подписание новых дополнений. Поэтому хорошо, что мы сохранили этот вариант. Оглядываясь назад, кажется, что можно было и оставить эту функцию, но оказалось, что она также конфликтует со смягчением «жёсткая прошивка даты», которую мы обсудим ниже (хотя в конечном итоге мы её не использовали). Итак, подписание новых дополнений теперь отложено.

Идея заключалась в том, чтобы защитить пользователей, которые ещё не прошли повторную проверку. Во-вторых, мы сразу выпустили быстрое исправление, которое подавляет повторную проверку подписей расширений. Мы сделали это до того, как у нас было какое-либо другое исправление, а теперь удалили, когда исправления доступны.

Параллельная работа

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

  1. Расширений очень много (более 15 000), и служба не оптимизирована для массовой подписи, поэтому просто повторное подписание каждого дополнения займёт больше времени, чем мы хотели.
  2. После того, как дополнения подписаны, пользователям будет необходимо получить новое дополнение. Некоторые размещены на серверах Mozilla, и Firefox обновит их в течение 24 часов, но пользователям придётся вручную обновлять любые аддоны, которые установлены из других источников, что очень неудобно.

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

Рассмотрев ряд подходов, мы быстро сошлись на двух основных стратегиях, которые мы проводили параллельно:

  1. Патч Firefox для изменения даты, используемой для проверки сертификата. В этом случае существующие дополнения волшебным образом снова заработают, но потребуется доставка новой сборки Firefox.
  2. Сгенерировать новый действительный сертификат и каким-то образом убедить Firefox принять его вместо существующего, просроченного.

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

Сертификат на замену

Как упоминалось выше, здесь нужно было выполнить два основных шага:

  1. Создать новый действительный сертификат.
  2. Удалённо установить его в Firefox.

Чтобы понять, почему это работает, вам нужно знать немного больше о том, как Firefox проверяет дополнения. Само дополнение поставляется в виде пакета файлов, который включает цепочку сертификатов, используемую для его подписания. В результате аддон независимо проверяется, если известен корневой сертификат, который настраивается в Firefox во время сборки. Однако, как я уже сказал, промежуточный сертификат был сломан, поэтому дополнение на самом деле не поддавалось проверке.

Вместо этого он пытается создать допустимую цепочку сертификатов, начиная с сертификата конечного объекта и продолжая до корневого каталога. Но оказывается, что когда Firefox пытается проверить расширение, он не ограничивается использованием только сертификатов в самом расширении. е. Алгоритм сложный, но на высоком уровне вы начинаете с сертификата конечного объекта, а затем находите сертификат, субъект которого равен эмитенту сертификата конечного объекта (т. В простом случае это только промежуточное звено, поставляемое с надстройкой, но это может быть любой сертификат, о котором знает браузер. промежуточного сертификата). На рисунке ниже показана ситуация до и после установки нового сертификата. Если мы можем удалённо добавить новый, действительный сертификат, Firefox также попытается построить такую цепочку.

Важной особенностью здесь является то, что новый сертификат имеет то же имя субъекта и открытый ключ, что и старый сертификат, так что его подпись на сертификате конечного объекта действительна. После установки нового сертификата Firefox имеет два варианта проверки цепочки сертификатов: использовать старый недействительный сертификат (что не сработает) или использовать новый действительный сертификат (что сработает). Обратите внимание, что это та же логика, которую мы используем для проверки сертификатов TLS, поэтому это относительно хорошо понятный код, который мы смогли использовать (читатели, знакомые с WebPKI, поймут, что так работает перекрёстная сертификация). К счастью, Firefox достаточно умён, чтобы попробовать оба способа, пока не найдёт рабочий, поэтому расширение снова становится действительным.

Когда мы установим новый сертификат в Firefox, то даже расширения со старыми сертификатами пройдут проверку. Самое замечательное в этом исправлении заключается в том, что оно не требует изменения каких-либо существующих расширений. Хитрость в поставке нового сертификата в Firefox, что нужно сделать автоматически и удалённо, а затем заставить Firefox перепроверить все расширения, которые, возможно, были отключены.

Normandy и система исследований

По иронии, решением проблемы стал специальный тип расширения под названием system add-on (SAO). Для исследований аудитории (Studies) ранее мы разработали систему под названием Normandy, которая умеет поставлять SAO пользователям Firefox. Эти SAO автоматически выполняются в браузере пользователя. Хотя они обычно используются для проведения экспериментов, но также обладают широким доступ к внутренним API в Firefox. В этом случае важно, что они могут добавить в базу сертификатов новые сертификаты, которые Firefox использует для проверки расширений (техническое примечание: мы не добавляем сертификат с какими-то специальными привилегиями; он получает свои привилегии за счёт подписи корневым сертификатом. Мы просто добавляем его в пул сертификатов, которые могут использоваться Firefox. Таким образом, мы не добавляем новый привилегированный сертификат в Firefox).

Итак, решение здесь — создать SAO, который делает две вещи:

  1. Устанавливает новый сертификат, который мы сделали.
  2. Заставляет браузер повторно проверить каждое дополнение, чтобы активировать те, которые отключились.

Но подождите, скажете вы. Дополнения не работают, как же заставить работать SAO? Ну, мы подпишем его новым сертификатом!

Собрать всё воедино… и почему так долго?

Итак, теперь у нас есть план: выпустить новый сертификат, чтобы заменить старый, построить системное дополнение, чтобы установить его в Firefox, и развернуть его в Normandy. Мы начали работу примерно с 18:00 PST в пятницу 3 мая, а отправили исправление в Normandy примерно в в 2:44 ночи, то есть менее чем через 9 часов, а затем потребовалось ещё 6-12 часов, прежде чем большинство пользователей его получили. На самом деле это очень хороший старт, но я видел в твиттере ряд вопросов, почему мы не смогли сделать это быстрее. Существует ряд шагов, которые отнимают много времени.

Как я уже упоминал выше, корневой сертификат находится в аппаратном модуле безопасности, который хранится в автономном режиме. Во-первых, потребовалось некоторое время для выдачи нового промежуточного сертификата. Но очевидно, это несколько неудобно, когда нужно выдать новый сертификат в чрезвычайной ситуации. Это хорошая практика безопасности, так как вы очень редко используете корневой сертификат, и поэтому хотите хранить его в безопасности. Затем было несколько фальстартов, когда мы не смогли выдать правильный сертификат, и каждая попытка стоила часа или двух тестирования, прежде чем мы точно понимали, что делать. Во всяком случае, одному из наших инженеров пришлось ехать в безопасное место, где хранится HSM.

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

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

Последние шаги

Хотя системный аддон, развёрнутый через систему Studies, должен исправить ситуацию у большинство пользователей, он дошёл не до всех. В частности, для нескольких типов пользователей требуется другой подход:

  • Пользователи, отключившие телеметрию или исследования.
  • Пользователи Firefox для Android (Fennec), где у нас нет исследований.
  • Пользователи последующих сборок Firefox ESR, которые не подпишутся на телеметрические отчеты.
  • Пользователи, которые находятся за HTTPS MiTM-прокси, потому что наши системы установки аддонов принудительно закрепляют ключи для этих соединений, что конфликтует с прокси.
  • Пользователи очень старых сборок Firefox, до которых система Studies не может достучаться.

Мы ничего не можем сделать с последней группой — им придётся обновиться до новой версии Firefox, потому что старые версии обычно имеют довольно серьёзные неисправленные уязвимости безопасности. Мы знаем, что некоторые люди остались на старых версиях Firefox, потому что хотят запускать расширения старого стиля, но многие из них теперь работают с более новыми версиями Firefox. Для других групп мы разработали патч для Firefox, который установит новый сертификат после обновления. Он также выпущен как новая версия Firefox «с точкой», поэтому люди должны её получить — и, вероятно, уже получили — через обычный канал обновления. Если у вас есть билд из нисходящего потока, вам нужно дождаться обновления от мейнтейнера.

В частности, в некоторых случаях пользователи теряют данные, связанные с аддонами (например, расширение типа «контейнеры с несколькими учётными записями»). Мы признаём, что ничто из этого не является совершенным.

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

Уроки

Во-первых, я хочу сказать, что команда здесь проделала удивительную работу: они разработали и отправили исправление менее чем за 12 часов с момента первоначального отчёта. Как человек, который присутствовал на собрании, где это произошло, я могу сказать, что люди работали невероятно усердно в трудной ситуации и что очень мало времени было потрачено впустую.

Нам явно нужно скорректировать наши процессы, чтобы уменьшить вероятность этого и подобных инцидентов и облегчить их исправление. С учётом сказанного, очевидно, что это не идеальная ситуация, и такое вообще не должно было случиться.

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

Отлично, что мы смогли задействовать систему Studies, но это тоже был не самый совершенный инструмент, который мы ввели в эксплуатацию, и который имел некоторые нежелательные побочные эффекты. Во-вторых, нужен механизм, чтобы быстро накатывать обновления пользователям, даже когда — особенно когда — всё остальное не работает. Какими бы ни были внутренние технические механизмы, у пользователей должна быть возможность выбрать обновления (включая исправления), но отказаться от всего остального. В частности, мы знаем, что у многих пользователей включены автоматические обновления, но они предпочли бы не участвовать в исследованиях, и это разумное предпочтение (да что говорить, я сам так настраивал браузер!), но в то же время мы должны иметь возможность пушить обновления. Даже в понедельник у нас ещё остались пользователи, которые не забрали исправление или новый релиз, что явно не идеально. Кроме того, канал обновлений должен работать более быстро. Над этой проблемой уже поработали, но этот инцидент показывает, насколько она важна.

Наконец, мы рассмотрим в более общем плане нашу архитектуру безопасности расширений, чтобы убедиться, что она корректно обеспечивает безопасность при минимальных рисках сбоев.

На следующей неделе мы опубликуем результаты более тщательного анализа этой ситуации.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть