Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Динамический рендеринг — это техника, которая используется, чтобы отдавать поисковикам и ботам заранее отрендеренные веб‑страницы. В этой статье я исследую, как две популярные утилиты для динамического рендеринга добавляют уязвимости в веб‑приложение, если настроены неправильно, и попробую объяснить, как я использовал уязвимость в одном из них, чтобы захватить сервер компании в рамках bug bounty.
Для создания сайтов и веб‑приложений активно применяются фреймворки JavaScript — вместо статичных страниц HTML теперь популярно делать PWA (progressive web apps) и SPA (single page applications), которые формируют большую часть контента в браузере пользователя. У этого подхода масса преимуществ, и на вебе это позволяет сделать отзывчивый интерфейс, но в то же время такой подход недружелюбен для SEO, потому что большинство поисковиков и ботов не понимают JavaScript и не могут рендерить страницы самостоятельно.
Один из распространенных способов помочь ботам в таком случае — это открыть запрашиваемую страницу в headless-браузере на стороне сервера, дождаться, пока страница отрисуется, и вернуть получившийся HTML, предварительно почистив его от лишних тегов. Этот метод и называется «динамический рендеринг» и сейчас активно продвигается компанией Google как возможность оптимизировать сайт для поиска.
Я наткнулся на этот тип приложений, когда проводил немного другое исследование: я искал уязвимости в модулях npm, которые используют headless-браузеры. Я написал правила для Semgrep (утилиты с открытыми исходниками, в разработке которой я принимаю участие) и применил их к тысячам модулей, которые используют Puppeteer, Playwright и PhantomJS в качестве зависимостей. Находок было много, и после расследования и разбора результатов я обнаружил множество модулей, помогающих веб‑мастерам в организации динамического рендеринга.
www
Мой набор правил для Semgrep
Популярность динамического рендеринга растет, поэтому будет небесполезно понять, что может пойти не так в продакшене при его использовании.
В своем исследовании я разобрал два самых популярных приложения для динамического рендеринга — Rendertron и Prerender, но описанные атаки можно использовать и для других приложений такого типа.
Также я немного расскажу о том, как мне удалось применить полученные знания при поиске уязвимостей в рамках bug bounty.
Один из возможных способов показать поисковому боту подходящий для индексации контент работает так: перехватывается запрос, страница рендерится на сервере, а результат в виде HTML со всем нужным содержимым возвращается боту.
<script>
и возвращается на сервер.
На каких страницах обычно используется динамический рендеринг? Эти страницы, скорее всего, будут в открытом доступе, поскольку цель динамического рендеринга — улучшить их индексируемость. Контент на этих страницах будет создаваться при помощи JavaScript, при этом данные на странице меняются динамически. Например, это может быть новостной сайт, который постоянно обновляется, или часто обновляемый список популярных продуктов в интернет‑магазине.
Когда потенциальная цель найдена, можно проверить, использует ли она динамический рендеринг, отправив несколько запросов с разными значениями заголовка User-Agent
.
Вот запрос, который притворяется Google Chrome:
curl -v -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36" https://shop.polymer-project.org/
А вот запрос якобы от бота Slack:
curl -v -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" https://shop.polymer-project.org/
Если ответы от сервера различаются, а ответ на запрос от поддельного краулера приходит в виде красивого HTML без тегов <script>
, это означает, что сайт использует динамический рендеринг.
www
В качестве подопытного я использовал демосайт Google для фреймворка Polymer. Под капотом у него Rendertron.
Сравниваем запросы
Подробности того, на какие конкретно значения User-Agent
реагирует приложение, можно посмотреть в исходном коде Rendertron (файл middleware.ts). Также Rendertron всегда возвращает заголовок X-Renderer: Rendertron
. Prerender может писать в ответах X-Prerender: 1
, но это не умолчательное поведение.
Оба фреймворка дают разработчикам возможность управлять заголовками ответа с помощью метатегов на странице. Это полезно для детекта динамического рендеринга.
Пример для Prerender:
<meta name="prerender-status-code" content="302" /><meta name="prerender-header" content="Location: https://www.google.com" />
Пример для Rendertron:
<meta name="render:status_code" content="404" />
Легче всего захватить приложение для динамического рендеринга, если оно доступно извне. Тогда можно взаимодействовать с ним напрямую и отправлять через него произвольные запросы, включая запросы к локальной инфраструктуре.
Существуют некоторые запреты на доступ к локальным адресам, но в зависимости от версии приложения их можно попробовать обойти.
Источник: xakep.ru