Меню
RU

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

Браузерное расширение 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.

Загружая комментарии, вы соглашаетесь с условиями использования и политикой конфиденциальности.
29 августа 2022 г.
Снова в школу: осенняя акция AdGuard
Встречайте нашу ежегодную акцию «Снова в школу». До 4 сентября вы можете купить любую лицензию AdGuard со скидкой 40%, а годовую подписку на AdGuard VPN на 75% дешевле. AdGuard очистит интернет от визуального мусора и сохранит ваши личные данные в безопасности.
Цифровое бессмертие: вечная жизнь или вечные муки?
У всех нас есть цифровые личности. Но что случится с ними после нашей смерти? Почему наши данные в опасности и как их защитить — читайте в статье.
Загрузка AdGuard началась Стрелка указывает на файл: нажмите на него, и установка начнётся Выберите «Открыть», нажмите «OK» и дождитесь загрузки файла. В открывшемся окне перетащите значок AdGuard в папку «Приложения». Спасибо за выбор AdGuard! Выберите «Открыть», нажмите «OK» и дождитесь загрузки файла. В открывшемся окне нажмите «Установить». Спасибо за выбор AdGuard!
AdGuard есть и в мобильном варианте