AdGuard выпускает первый в мире блокировщик, работающий на Manifest V3
Manifest V3, новый API расширений от Chrome, больше не иллюзорная угроза. Теперь он – новая реальность, в которой предстоит работать (или не работать) десяткам расширений по блокировке рекламы, в том числе и Браузерному расширению AdGuard.
Волна Manifest V3 нарастала постепенно, но неотвратимо. В 2018 году, когда Google только обнародовал документ с описанием нового API, сообщество разработчиков разразилось критикой. Мы тоже не остались в стороне и опубликовали несколько статей, в которых рассказали о возможных негативных последствиях внедрения Manifest V3 и даже выразили надежду, что «всё сложится не так плохо».
Несмотря на общественный резонанс, Manifest V3 стал доступен в конце 2020 года вместе с Chrome 88 Beta. С января 2022 стало невозможно добавлять в Chrome Web Store новые расширения, использующие Manifest V2. Последний этап запуска наступит очень скоро: с января 2023 года все расширения на Manifest V2 перестанут работать, даже те, что были добавлены в Chrome Web Store ранее.
Если вы используете AdGuard для Windows, Mac или Android, вам вообще не стоит волноваться о Manifest V3. Эти продукты не подвержены браузерным ограничениям.
К счастью, мы к этому готовы.
Экспериментальное Браузерное расширение AdGuard MV3
В середине 2021 года мы начали работать над прототипом нового расширения, которое сможет качественно блокировать рекламу даже в жёстких рамках Manifest V3. Задача оказалась не из лёгких: новый API всё ещё сыроват, некоторые вещи дорабатываются и не действуют так, как были задуманы. Но мы, конечно же, справились – и доказали, что блокировщики рекламы выживут даже с наступлением апокалипсиса, имя которому – Manifest V3.
Во время разработки прототипа мы столкнулись с большим количеством серьёзных проблем, вызванных особенностями нового API: какие-то удалось преодолеть, а с чем-то пришлось смириться. Мы хотим подробно рассказать о каждой из них.
Тем временем, вы можете попробовать наш прототип установив его из Chrome WebStore.
Короткая видеодемонстрация работы нового расширения
Ограничение количества правил
Manifest V3 разделил правила, входящие в фильтры расширения, на статические (встроенные) и динамические и резко ограничил их количество. Исключение составили лишь косметические правила, которые применяются отдельно.
Для статических правил Chrome установил минимальный гарантированный лимит в 30 000 правил для каждого расширения и общий лимит в 330 000 правил для всех расширений, установленных одним пользователем (здесь же учитывается ограничение в 1000 регулярных выражений на расширение). Хитрость в том, что весь разрешённый объём правил может достаться одному блокировщику, а может нескольким – и тогда, возможно, какому-то расширению может не хватить лимита.
Если это произойдёт с нашим расширением (а это может случиться в любой момент, например, после обновления, перезапуска service worker, изменения набора фильтров в нашем или сторонних блокировщиках), оно покажет сообщение о том, что браузер изменил набор активных фильтров и оставил включённым только базовый рекламный фильтр. В худшем случае даже базовый фильтр может не включиться: тогда пользователь в принципе останется без защиты AdGuard.
Все эти случаи предусмотрены нами и отображаются на отдельном экране с описанием того, что именно браузер отключил и что включил.
Для динамических правил, в рамках которых пользователь может добавлять собственные правила или фильтры, установлен крошечный лимит в 5000, включая ограничение в 1000 регулярных выражений.
Сообщения об израсходовании лимита и отсечении правил будут выглядеть так:
Ограничения Manifest V3 наносят вред не только качеству фильтрации и удобству пользователей, но и сообществу разработчиков фильтров. Раньше любой человек мог создать фильтр под себя, и со временем такой фильтр мог стать популярным и войти в список рекомендованных у блокировщиков. Теперь достигнуть этого значительно сложнее. Ведь блокировщики должны использовать предустановленные фильтры (не более 50), и нам приходится очень выборочно подходить к тому, какие фильтры будут доступны пользователям. Конечно, вы всё ещё можете установить собственный фильтр вручную. Но не забывайте про ограничение в 5000 правил на все собственные фильтры.
Дальнейшее описание проблем включает массу подробностей, понятных в основном разработчикам. Если вы не технический специалист, можете смело пропустить эту часть.
Декларативные правила
До введения ограничений Manifest V3 движок фильтрации собирался динамически из фильтров, которые расширение скачивало с сервера. Дальше правила, составляющие фильтры, применялись на разных этапах загрузки страницы.
Например, правила могли сработать ещё до отправки запроса браузером: запускалось событие onBeforeRequest
, где браузер спрашивал, что делать с тем или иным запросом, а расширение в динамике отдавало ответ о его блокировке или перенаправлении. Косметические правила применялись чуть позже, уже когда страница подгрузилась и появился DOM.
Теперь, когда Manifest V3 вступил в силу, метод onBeforeRequest
больше нельзя применить. Вместо него Chrome предлагает использовать declarativeNetRequest API
, с которым право на модификацию запросов передаётся браузеру. Расширение только объявляет набор декларативных правил, в соответствии с которыми браузер будет изменять или блокировать сетевые запросы.
Синтаксис декларативных правил
Синтаксис декларативных правил сильно отличается от синтаксиса, который обычно используют разработчики фильтров. Возможно, многие члены сообщества откажутся от работы в рамках Manifest V3, не желая тратить время на создание правил, заточенных исключительно под Chrome.
Каждое правило должно состоять из следующих полей:
id
– идентификатор правила. Его можно использовать, чтобы связать декларативное правило с текстовым правиломpriority
– приоритет правила. Он определяет порядок применения правила к запросуaction
– действие правила
бывают трех видов:block
– действия, которые блокируют запросыredirect
илиupgradeScheme
– действия, которые перенаправляют запросыallow
илиallowAllRequests
– действия, которые разрешают запросы
condition
– условие, по которому применяется правило
Пример правила:
{
"id": 1,
"priority": 1,
"action": { "type" : "block" },
"condition": {
"urlFilter": "abc",
"domains": ["example.org"],
"resourceTypes": ["script"]
}
}
Это правило будет блокировать все запросы к скриптам, которые имеют в адресе подстроку abc
и исходят от сайта с доменом example.org
.
Сложившаяся ситуация вызывает у нас острое чувство дежавю: при разработке расширения, блокирующего рекламу в Safari, нам пришлось придумать способ конвертировать синтаксис наших правил в синтаксис, навязанный разработчиками браузера. В этот раз мы используем аналогичное решение, чтобы превратить наш синтаксис в декларативные правила Chrome.
Для конвертации статических и динамических правил мы добавили модуль в свою библиотеку @adguard/tsurlfilter. Библиотека проходится по правилам фильтра и преобразует их в декларативные правила, которые объединяет в наборы правил и складывает их в json-файлы. Чтобы не потерять связь между текстовым правилом и json-правилом, библиотека строит таблицу соответствия между ними.
Несколько примеров работы конвертера:
Правило ||example.com^$script
конвертируется в
{
"id": 1,
"action": {
"type": "block"
},
"condition": {
"urlFilter": "||example.com^",
"resourceTypes": [
"script"
],
"isUrlFilterCaseSensitive": false
}
}
Правило @@||example.com^$script$domain=example.org
конвертируется в
{
"priority": 1,
"id": 23,
"action": {
"type": "allow"
},
"condition": {
"urlFilter": "||example.com^$script",
"initiatorDomains": [
"example.org"
],
"isUrlFilterCaseSensitive": false
}
}
Большая часть правил сконвертируется корректно, но небольшая часть функциональности будет потеряна из-за разнообразных ограничений:
$removeparam
не поддерживает исключения (~) и регулярные выражения (regexp)- Для регулярных выражений Chrome использует собственную имплементацию таких выражений, из-за чего часть стандартного функционала не поддерживается. Например, это регулярные выражения, содержащие обратные ссылки (backreference), отрицательный поиск вперёд (negative lookahead), квантификаторы (possessive quantifiers).
negative lookahead
часто применяется в фильтрах. быстрый поиск показал, что сейчас в фильтрах есть 43 правила с этим выражением. На первый взгляд это довольно мало, но учтите, что каждое из этих правил расчитано на работу на нескольких сайтах — одно это ограничение уже мешает работе блокировщиков на более чем 1000 сайтов.- Регулярные выражения дополнительно валидируются внутри Chrome на количество потребляемой памяти. Поскольку нам не совсем понятно, какая именно имплементация при этом используется, могут возникать проблемы с регулярными выражениями.
- Не поддерживаются cookie-правила.
- Существует ещё множество проблем, которые мы не упоминаем здесь, чтобы не замусоривать пост.
Проблема декларативных правил вполне очевидна: их синтаксис сильно ограничивает возможности нашего расширения. И, к сожалению, с этим ничего нельзя сделать, разве что надеяться, что разработчики Chrome со временем его улучшат.
Наборы правил
Согласно новому API декларативные правила должны объединяться в наборы правил (rulesets).
Пример подключения набора правил в Manifest V3:
{
"name": "AdGuard AdBlocker MV3",
"version": "1",
"declarative_net_request": {
"rule_resources": [{
"id": "ruleset_1",
"enabled": true,
"path": "rules.json"
}]
},
…
}
Наборы правил указываются в файле manifest.json и подгружаются только в момент установки расширения или его обновления. И это большая проблема.
Бывает так, что правило фильтрации ломает вёрстку или работоспособность одного или нескольких сайтов. Это нормально: невозможно отловить все ошибки в невероятном количестве правил, да и на сайтах постоянно что-то меняется, что может приводить к возникновению проблем.
Предположим, что в фильтр попало такое правило, и его надо быстро отключить. В расширении на Manifest V2 для этого использовался модификатор $badfilter
. Разработчики фильтров добавляли правило с указанным модификатором, расширение динамически получало обновление, новое правило отключало правило, на которое ссылалось, и жизнь налаживалась. Как вы понимаете, такой «фокус» c Manifest V3 не пройдёт.
Теперь ждать обновления фильтров, возможно, придётся по несколько дней: ведь мало добавить в Chrome Store новую версию расширения, надо ещё дождаться прохождения ревью. Увы, другого способа предоставить пользователям обновлённые фильтры нет.
Небольшую надежду даёт дискуссия о возможности включения и выключения отдельных правил. Есть шанс, что расширениям всё же дадут возможность быстро обновлять фильтры.
Статистика и журнал фильтрации
В Браузерном расширении AdGuard на основе Manifest V2 есть Журнал фильтрации, где отражены все запросы, отправляемые браузером, и подробная информация о них. В том числе, там видно, каким фильтром и каким правилом был заблокирован тот или иной запрос.
Из-за того, что теперь Chrome сам блокирует запросы, а статистикой делится только с расширениями, распакованными и установленными в Режиме разработчика, мы не можем реализовать Журнал фильтрации в привычном виде. Зато можем придумать интересную альтернативу – что мы и планируем сделать в финальном расширении.
Итак, при открытии Журнала фильтрации будет запускаться движок, работающий по правилам Manifest V2. Он не будет ничего делать с запросами, только показывать, какие правила могли быть применены. Сравнивая статистику Chrome и результаты работы старого движка, мы будем получать примерную картину обработки запросов.
В текущей версии прототипа журнал фильтрации не реализован. Вместо этого, разработчикам фильтров придётся использовать механизм, рекомендованный разработчиками Chrome. Дело в том, что declarativeNetRequest
всё-таки позволяет получить информацию о том, какое правило сработало. Но есть один нюанс: для этого нужно установить расширение в «распакованном» виде. То есть, нужно будет склонировать наш репозиторий, «сбилдить» расширение, переключить браузер в режим разработчика и только в этом случае вы сможете воспользоваться средствами для отладки фильтров.
Service worker
Вместе с Manifest V2 в прошлое ушла и фоновая страница (background page). Благодаря ей расширение один раз запускалось после установки или при открытии браузера – и работало в фоне. В Manifest V3 эту страничку заменил так называемый service worker, работа которого часто прерывается браузером.
Когда браузер останавливает service worker, расширение уходит в некоторое подобие спящего режима: декларативные правила функционируют, а вот косметические правила, которые мы подгружаем динамически – нет. Чтобы приложение начало работать, что-то должно разбудить service worker: это может быть загрузка страницы или сообщение, которое было отправлено на service worker.
Когда service worker возвращается в рабочее состояние, расширение начинает считывать правила фильтров из хранилища и обрабатывать их, чтобы затем иметь возможность их быстро находить. В это время – в течение 1,5-2 секунд (при первичной установке около 3 секунд) – расширение не блокирует рекламу косметически, но рекламные запросы при этом блокируются самим браузером. Затем движок запускается, и реклама исчезает.
Мы планируем сократить время пробуждения service worker и постараемся перенести применение большей части косметических правил в “content script” (который работает в контексте самой страницы), но для некоторых случаев нам все равно будет нужен именно service worker.
Заключение
Несмотря на все ограничения Manifest V3, AdGuard MV3 достаточно хорошо защищает от рекламы и трекинга:
- превентивно блокирует запросы к трекерам
- скрывает рекламные баннеры, виджеты социальных сетей и другие раздражающие элементы
- блокирует рекламу на видеохостингах, в том числе и на YouTube
Пусть экспериментальное расширение не столь эффективно, как его предшественник, но большинство пользователей не почувствуют разницы. Единственное, что можно будет заметить — мелькание рекламы из-за задержки в применении косметических правил.
Наша цель с этим прототипом — протестировать новый подход и получить обратную связь. Так что, пожалуйста, попробуйте новое расширение и расскажите нам, что в нём можно улучшить. Как обычно, мы открываем исходный код прототипа, вы можете найти его на Github. Если у вас будут с ним какие-то проблемы или если вы хотите что-то предложить, расскажите нам об этом через Issue на GitHub.
Выпуская сегодня экспериментальное расширение на базе Manifest V3 – первыми среди разработчиков блокировщиков рекламы – мы можем сказать, что справились с вызовом, который нам бросил Google. Да, впереди ещё много работы, но уже сейчас можно с уверенностью сказать, что даже после отмены Manifest V2 пользователи браузера Google Chrome смогут оградить себя от рекламы и трекеров с помощью Браузерного расширения AdGuard.