Avatar ·

Зачем Google добавляет while(1); в начало своих JSON-ответов?

Всем привет! Я начинающий фронтенд-разработчик, и недавно столкнулся с интересной особенностью при работе с API Google. Когда я делаю запрос к некоторым их эндпоинтам, например, к Google Calendar API или Google Suggest, в ответе я вижу странную конструкцию: `while(1);` перед самим JSON. Вот пример того, как выглядит ответ: ``` while(1); {"items": [{"id": 1, "name": "test"}]} ``` Я сначала подумал, что это какая-то ошибка или баг. Попробовал распарсить такой ответ через `JSON.parse()` — естественно, получил ошибку, потому что `while(1);` не является валидным JSON. Мне пришлось написать костыль, чтобы обрезать эту приставку: ```javascript fetch('https://some-google-api.com/data') .then(response => response.text()) .then(text => { const json = text.replace(/^while\(1\);/, ''); const data = JSON.parse(json); console.log(data); }); ``` Но это кажется очень странным и неочевидным решением. Зачем Google вообще добавляет этот `while(1);`? Ведь это только усложняет парсинг на клиенте. Может быть, это какая-то защита от взлома? Или просто исторический артефакт? Объясните, пожалуйста, для чего это нужно и как правильно обрабатывать такие ответы. Заранее спасибо! <<>>

Зачем Google добавляет while(1); к JSON-ответам?

Это не баг и не случайность. Google использует эту конструкцию для защиты от атаки типа JSON Hijacking (JSON-угон). Давайте разберёмся, как это работает и почему это необходимо.

Что такое JSON Hijacking?

Раньше, до появления современных стандартов безопасности (CORS, SameSite cookies), злоумышленники могли украсть данные из JSON-ответов, используя тег <script>. Вот как это работало:

  1. Пользователь залогинен на сайте (например, в почте Google).
  2. Злоумышленник размещает на своём сайте такой код:
<script>
// Переопределяем конструктор Array
Array = function() { 
  // Перехватываем данные
};
</script>
<script src="https://mail.google.com/mail/feed/atom"></script>

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

Как while(1); защищает?

Добавляя while(1); в начало ответа, Google превращает JSON в невалидный JavaScript. Если злоумышленник попытается загрузить этот ответ через <script>, выполнение скрипта зависнет в бесконечном цикле, и данные не будут украдены.

При этом легитимные запросы через fetch или XMLHttpRequest всё равно могут получить "сырой" текст ответа, обрезать префикс и распарсить JSON.

Как правильно обрабатывать такие ответы?

Ваш подход с replace рабочий, но лучше использовать более надёжный способ:

fetch('https://example.com/api/data')
  .then(response => response.text())
  .then(text => {
    // Убираем while(1); и любые другие префиксы
    const jsonStr = text.replace(/^\)\]\}',?\n?/, '').replace(/^while\(1\);/, '');
    try {
      const data = JSON.parse(jsonStr);
      console.log('Данные:', data);
    } catch (e) {
      console.error('Ошибка парсинга JSON:', e);
    }
  });

Обратите внимание: Google иногда использует и другие префиксы, например )]}' (для Google Data API). Лучше использовать универсальное регулярное выражение.

Современная альтернатива

Сейчас, с появлением CORS и SameSite cookies, эта проблема частично решена на уровне браузеров. Однако Google продолжает использовать while(1); для обратной совместимости и дополнительной защиты:

  • CORS — запрещает чтение ответа с другого домена, если сервер не разрешил это явно.
  • SameSite cookies — не даёт отправлять куки с кросс-доменными запросами.

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

Итог

while(1); — это дешёвый и эффективный способ предотвратить утечку данных через JSON Hijacking. Он гарантирует, что ответ нельзя выполнить как скрипт, но при этом его можно прочитать и обработать программно.

<<>>

Дополнение: другие способы защиты от JSON Hijacking

Помимо while(1);, существуют и другие методы защиты, которые вы можете встретить в разных API:

  • Префикс )]}' — используется в Google Data API. Работает по тому же принципу: делает ответ невалидным JavaScript.
  • Обёртка в комментарий — например, /**/{"data": "value"}. Комментарий не выполняется, но JSON остаётся парсибельным.
  • Использование POST вместо GET — атака JSON Hijacking возможна только через GET-запросы (через тег <script>). POST-запросы не могут быть выполнены таким образом.

Если вы разрабатываете своё API, рекомендую:

  1. Всегда использовать X-Content-Type-Options: nosniff в заголовках.
  2. Добавлять префикс )]}' к JSON-ответам (это стало де-факто стандартом).
  3. Проверять заголовок Content-Type на сервере — не доверять запросам с неправильным типом.

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