Бывает расхождение, которое не ловится ни code review, ни аудитом зависимостей: в системе контроля версий лежит одно, а посетитель получает другое. Никакого взлома, никакой подмены DNS, никакого зловреда в сборке — между сервером и читателем просто стоит прокси, у которого есть техническая возможность править разметку на лету.
Классическая иллюстрация всплыла на днях: у владельца сайта, где вообще не используется JavaScript, в исходном коде страницы обнаружился чужой <script> с домена Cloudflare. Обсуждение получилось шумным, а мнения разделились надвое — «у меня ровно то же» против «это известное поведение прокси, вы сами его включили».
Правда лежит посередине, и разбирать её удобнее по шагам: что именно дописывается, при каком условии это вообще возможно, какие ещё функции переписывают HTML на границе сети и где спрятан выключатель — он находится совсем не в настройках домена.
Как выглядит проблема
В отдаваемом браузеру HTML перед закрывающим </body> появляется тег, отсутствующий в исходниках проекта:
Обнаруживают его обычно не глазами, а по косвенным признакам: в консоли браузера с активной усиленной защитой от отслеживания появляется Cross-Origin Request Blocked, а при жёсткой политике безопасности контента скрипт блокируется с соответствующей ошибкой. В подробном разборе на burgeonlab описан характерный случай: скрипт присутствовал на двух доменах из трёх примерно пять месяцев, и заметили его только из-за этих ошибок.
Диагностируется одной командой. Принципиально смотреть на то, что реально отдаёт граничный узел, а не на содержимое файлов на диске:
Виновник — Cloudflare Web Analytics, она же система RUM. Раздел документации Enabling Cloudflare Web Analytics формулирует это без обиняков: для проксируемых через Cloudflare сайтов автоматическая установка активна изначально, и beacon-скрипт добавляется без участия владельца. Масштаб уточняет FAQ: автоматический режим «вставляет JS-сниппет на всех страницах (поддоменах) в пределах зоны».
❗ Главное
Здесь важна поправка, которая теряется в громких пересказах: причина не в переезде NS-серверов как таковом. Дописать что-либо в ответ можно только там, где Cloudflare завершает TLS-соединение и физически держит тело ответа, — то есть при включённом «оранжевом облаке» (Proxied) у DNS-записи. В режиме DNS only клиент получает адрес вашего сервера напрямую, трафик идёт мимо инфраструктуры Cloudflare, и вмешательство исключено.
Смешение возникает по простой причине: при подключении домена проксируемый режим предлагается по умолчанию, так что «я поменял NS» и «я включил прокси» для большинства случаются одним действием.
Схема на основе документации developers.cloudflare.com — разделы Web Analytics и DNS proxy status
Соседи по разметке
Если уж речь о правке HTML на границе, полезно знать весь набор функций, способных туда вмешаться. Все они описаны в документации и все отключаются, но состояние по умолчанию у них разное — и это как раз то, что чаще всего застаёт врасплох:
Функция
Что делает с HTML
Включено по умолчанию
Web Analytics (RUM)
вставляет beacon.min.js перед </body>
да, для проксируемых зон
Email Address Obfuscation
заменяет адреса почты и подключает email-decode.min.js
переписывает теги <script>, откладывая исполнение JS
нет, включается вручную
📌 Заметка
Обфускация почты недооценена сильнее прочего. Дело не в подключаемом скрипте, а в том, что функция меняет саму разметку: почтовый адрес превращается в <a href="/cdn-cgi/l/email-protection#...">. Если контакты со страницы разбирает внешний сервис или проверяет автотест, вот вам объяснение, почему локально всё зелёное, а на боевом домене — нет.
Как это выключить
Настройка живёт на уровне аккаунта, а не отдельной зоны, — поэтому её и не находят там, где обычно ищут:
✅ Как правильно
откройте панель Cloudflare на уровне аккаунта, а не конкретного сайта;
перейдите в Analytics & Logs → Web Analytics;
напротив нужного домена нажмите Manage site;
выберите режим и подтвердите кнопкой Update.
Документация описывает три режима:
Enable — вставка активна; отдельным вариантом идёт исключение посетителей из ЕС;
Enable with JS Snippet installation — автоматической вставки нет, сниппет устанавливается вручную;
Disable — вставки не происходит.
Есть обходной путь через кэш-политику: по документации автоматическая вставка не срабатывает, когда origin присылает заголовок Cache-Control: public, no-transform — прокси в этом случае не вправе трогать полезную нагрузку. Приём работает, но менять кэш-политику целого сайта ради одного скрипта — сомнительный размен. Крайняя мера — перевести запись в DNS only, однако вместе с проксированием исчезнут WAF, кэширование и защита от DDoS, то есть ровно то, ради чего Cloudflare обычно и подключают.
⚠️ Осторожно
Строгая политика безопасности контента почти наверняка вступит в конфликт. Документация Cloudflare требует: при автоматической вставке в connect-src должно быть 'self' (данные уходят на тот же домен), при ручной — в connect-src нужен cloudflareinsights.com, а в script-src — https://static.cloudflareinsights.com/beacon.min.js. Иначе говоря, придётся выбирать между ошибками в консоли и ослабленной политикой; промежуточного варианта нет.
🔒 Безопасность
Юридическая сторона галочкой не закрывается. Когда сайт обслуживает посетителей из ЕС, а баннер согласия составлялся под известный перечень скриптов, скрипт, появившийся без ведома владельца, в этот перечень не попал. У Cloudflare есть режим «Enable, excluding visitor data in the EU», и в спорной ситуации компромиссом чаще оказывается именно он, а не полное отключение, — своя аналитика при этом продолжает работать. Но контроль за тем, что уходит со страниц, остаётся обязанностью владельца сайта: прокси эту задачу не решает.
В чём тут собственно новость
Строго говоря — ни в чём, кроме количества удивлённых. Поведение задокументировано публично, выключается за четыре клика, багом и уязвимостью не является. Показательно другое: модель «по умолчанию включено, отключайте сами», применённая на инфраструктурном уровне, остаётся невидимой почти для всех, кроме тех немногих, кто периодически смотрит в исходник собственной страницы.
Отсюда обобщение, годное для любого посредника между вашим сервером и читателем: после смены хостинга, CDN или тарифного плана имеет смысл один раз сличить вывод curl по своему домену с тем, что лежит в репозитории. Занимает секунды, а результат порой удивляет.
Проверьте свои домены — любопытно, у скольких beacon висит не первый год. И вопрос по существу: где для вас граница дозволенного для CDN? Отложить исполнение <script> ради скорости — приемлемо, а добавить собственный тег — уже нет? Или раз вы отдали посреднику ключи от TLS, разницы никакой?
Вы можете написать сейчас и зарегистрироваться позже.
Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.
Бывает расхождение, которое не ловится ни code review, ни аудитом зависимостей: в системе контроля версий лежит одно, а посетитель получает другое. Никакого взлома, никакой подмены DNS, никакого зловреда в сборке — между сервером и читателем просто стоит прокси, у которого есть техническая возможность править разметку на лету.
Классическая иллюстрация всплыла на днях: у владельца сайта, где вообще не используется JavaScript, в исходном коде страницы обнаружился чужой
<script>с домена Cloudflare. Обсуждение получилось шумным, а мнения разделились надвое — «у меня ровно то же» против «это известное поведение прокси, вы сами его включили».Правда лежит посередине, и разбирать её удобнее по шагам: что именно дописывается, при каком условии это вообще возможно, какие ещё функции переписывают HTML на границе сети и где спрятан выключатель — он находится совсем не в настройках домена.
Как выглядит проблема
В отдаваемом браузеру HTML перед закрывающим
</body>появляется тег, отсутствующий в исходниках проекта:Обнаруживают его обычно не глазами, а по косвенным признакам: в консоли браузера с активной усиленной защитой от отслеживания появляется
Cross-Origin Request Blocked, а при жёсткой политике безопасности контента скрипт блокируется с соответствующей ошибкой. В подробном разборе на burgeonlab описан характерный случай: скрипт присутствовал на двух доменах из трёх примерно пять месяцев, и заметили его только из-за этих ошибок.Диагностируется одной командой. Принципиально смотреть на то, что реально отдаёт граничный узел, а не на содержимое файлов на диске:
Откуда он берётся
Виновник — Cloudflare Web Analytics, она же система RUM. Раздел документации Enabling Cloudflare Web Analytics формулирует это без обиняков: для проксируемых через Cloudflare сайтов автоматическая установка активна изначально, и beacon-скрипт добавляется без участия владельца. Масштаб уточняет FAQ: автоматический режим «вставляет JS-сниппет на всех страницах (поддоменах) в пределах зоны».
❗ Главное
Здесь важна поправка, которая теряется в громких пересказах: причина не в переезде NS-серверов как таковом. Дописать что-либо в ответ можно только там, где Cloudflare завершает TLS-соединение и физически держит тело ответа, — то есть при включённом «оранжевом облаке» (Proxied) у DNS-записи. В режиме DNS only клиент получает адрес вашего сервера напрямую, трафик идёт мимо инфраструктуры Cloudflare, и вмешательство исключено.
Смешение возникает по простой причине: при подключении домена проксируемый режим предлагается по умолчанию, так что «я поменял NS» и «я включил прокси» для большинства случаются одним действием.
Соседи по разметке
Если уж речь о правке HTML на границе, полезно знать весь набор функций, способных туда вмешаться. Все они описаны в документации и все отключаются, но состояние по умолчанию у них разное — и это как раз то, что чаще всего застаёт врасплох:
beacon.min.jsперед</body>email-decode.min.js<script>, откладывая исполнение JS📌 Заметка
Обфускация почты недооценена сильнее прочего. Дело не в подключаемом скрипте, а в том, что функция меняет саму разметку: почтовый адрес превращается в
<a href="/cdn-cgi/l/email-protection#...">. Если контакты со страницы разбирает внешний сервис или проверяет автотест, вот вам объяснение, почему локально всё зелёное, а на боевом домене — нет.Как это выключить
Настройка живёт на уровне аккаунта, а не отдельной зоны, — поэтому её и не находят там, где обычно ищут:
✅ Как правильно
Документация описывает три режима:
Есть обходной путь через кэш-политику: по документации автоматическая вставка не срабатывает, когда origin присылает заголовок
Cache-Control: public, no-transform— прокси в этом случае не вправе трогать полезную нагрузку. Приём работает, но менять кэш-политику целого сайта ради одного скрипта — сомнительный размен. Крайняя мера — перевести запись в DNS only, однако вместе с проксированием исчезнут WAF, кэширование и защита от DDoS, то есть ровно то, ради чего Cloudflare обычно и подключают.⚠️ Осторожно
Строгая политика безопасности контента почти наверняка вступит в конфликт. Документация Cloudflare требует: при автоматической вставке в
connect-srcдолжно быть'self'(данные уходят на тот же домен), при ручной — вconnect-srcнуженcloudflareinsights.com, а вscript-src—https://static.cloudflareinsights.com/beacon.min.js. Иначе говоря, придётся выбирать между ошибками в консоли и ослабленной политикой; промежуточного варианта нет.🔒 Безопасность
Юридическая сторона галочкой не закрывается. Когда сайт обслуживает посетителей из ЕС, а баннер согласия составлялся под известный перечень скриптов, скрипт, появившийся без ведома владельца, в этот перечень не попал. У Cloudflare есть режим «Enable, excluding visitor data in the EU», и в спорной ситуации компромиссом чаще оказывается именно он, а не полное отключение, — своя аналитика при этом продолжает работать. Но контроль за тем, что уходит со страниц, остаётся обязанностью владельца сайта: прокси эту задачу не решает.
В чём тут собственно новость
Строго говоря — ни в чём, кроме количества удивлённых. Поведение задокументировано публично, выключается за четыре клика, багом и уязвимостью не является. Показательно другое: модель «по умолчанию включено, отключайте сами», применённая на инфраструктурном уровне, остаётся невидимой почти для всех, кроме тех немногих, кто периодически смотрит в исходник собственной страницы.
Отсюда обобщение, годное для любого посредника между вашим сервером и читателем: после смены хостинга, CDN или тарифного плана имеет смысл один раз сличить вывод
curlпо своему домену с тем, что лежит в репозитории. Занимает секунды, а результат порой удивляет.Источники
💬 Вопрос к сообществу
Проверьте свои домены — любопытно, у скольких beacon висит не первый год. И вопрос по существу: где для вас граница дозволенного для CDN? Отложить исполнение
<script>ради скорости — приемлемо, а добавить собственный тег — уже нет? Или раз вы отдали посреднику ключи от TLS, разницы никакой?TOP HOSTERS: KAMATERA (30 дней бесплатного теста!)
Универсальный хостер №1 - 4VPS.su (2Гб\с сервера) - 10% скидка на первый заказ или 15% бонус на первое пополнение