Можно ли защитить jsonp с помощью токена csrf?

#jsonp #csrf

#jsonp #csrf

Вопрос:

Пример использования: В ситуации с тем же доменом я хочу использовать jsonp для передачи данных просто потому, что это происходит раньше в запросе, чем любая передача ajax или iframe. Кроме того, я хочу, чтобы эти данные кэшировались как обычный js-файл.

Я не хочу предоставлять эти данные другим доменам.

Итак, я подумал о следующих приемах предотвращения csrf:

  1. Токен csrf, отправленный в качестве параметра GET вместе с запросом.
  2. Другой токен csrf, который сохраняется в переменной перед выполнением jsonp. Таким образом, jsonp вызовет функцию, только если обнаружит, что эта переменная имеет правильное значение.

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

Вопросы были бы:

  • Безопасно ли отправлять токен csrf в параметре GET? Или что я могу сделать, чтобы сделать его безопасным?
  • Может ли кто-нибудь из другого домена заглянуть в исходный код js, чтобы обойти трюк номер (2)?

Чтобы избежать того, что мы начинаем с нуля, вот документ, который я нахожу полезным:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_ (CSRF)_Prevention_Cheat_Sheet
(но, возможно, я что-то там пропустил)

Особенно интересно: «Раскрытие токена в URL», которое, я думаю, я все еще не полностью понял во всех его последствиях.

РЕДАКТИРОВАТЬ:
Другие решения, которые можно придумать:

3. проверка реферера. Недостаточно безопасно, afaik. Особенно, если файл js кэширован в браузере.
4. Шифрование. Вероятно, это не стоит затраченных усилий..

РЕДАКТИРОВАТЬ II:
Чтобы уточнить: «ситуация с одним и тем же доменом» просто означает, что html-страница и jsonp обслуживаются из одного домена. Клиентский компьютер может находиться где угодно.

ПРАВКА III:
я хочу быть таким же безопасным, как если бы я обслуживал обычный json или html / xml (который запрашивается с помощью ajax или iframe) вместо jsonp. Как вы, вероятно, знаете, json и html / xml защищены политикой одного и того же источника, в то время как jsonp — нет.

Я хочу использовать токены csrf для достижения такой же защиты с помощью jsonp. Токены csrf, очевидно, будут передаваться вместе с HTML-страницей.

ПРАВКА IV:
Вот как выглядел бы трюк номер 2.
Страница html:

 <script type="text/javascript">
  var token1 = 'upoihjvpaoijpoj';
</script>
<script type="text/javascript" src="xyz/jsonp.js?token2=o8976987698540"></script>
  

А затем в xyz /json.js?token2=..:

 if (token1 == 'upoihjvpaoijpoj') {
  json_callback(data);
}
  

РЕДАКТИРОВАТЬ V:
Этот вопрос достаточно сложный, поэтому, по крайней мере, я должен добавить реальный пример. Я не помню точный вариант использования, когда я публиковал этот вопрос, поэтому я просто пишу что-то, что действительно подходит.

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

Первой идеей было бы загрузить меню с помощью запроса XHR. На стороне сервера мы можем проверить файл cookie / сеанс, чтобы проверить, вошел ли пользователь в систему, и предоставить персонализированное меню.

Но XHR может начать загружаться только после того, как остальная часть страницы уже будет там. Javascript, с другой стороны, может начать загрузку, как только браузер проанализирует заголовок html. Таким образом, мы могли бы надеяться на повышение производительности, если бы мы обслуживали данные меню с помощью javascript / jsonp вместо XHR.

Теперь сценарий CSRF:

  • Пользователь входит в систему, чтобы oursite.com , который создает файл cookie сеанса.
  • Затем тот же пользователь посещает сайт злоумышленника evil.com , который содержит тег script для запроса (персонализированного) oursite.com/menudata.js .
  • Из-за политики того же источника скрипты на evil.com невозможно напрямую проверить содержимое menudata.js . Вместо этого он просто выполнит menudata.js .

menudata.js может выглядеть следующим образом:

 spawnMenu({...});
  

Или «spawnMenu» может быть динамически выбранной строкой на основе параметров запроса.
Если menudata.js выполняется на evil.com Злоумышленники, работающие на этом сайте, могли предоставить функцию с таким именем, а затем «позвонить домой» и украсть персонализированные данные меню.

Теперь идея (пункт 2. первоначального вопроса) заключалась в том, чтобы сделать что-то подобное вместо этого в menudata.js:

 if (secret_var === 'opijpoijpoizvnpoiq92823pjnfn') {
  spawnMenu({...});
}
  

На первый взгляд это выглядит вполне нормально. evil.com не знает secret_var, поэтому, когда menudata.js выполняется, он ничего не сделает.

Но потом, я слышал, что есть несколько неприятных трюков, с помощью которых вы можете «переписать» довольно базовые части js. Например, заменить обычный способ преобразования содержимого в строку. Может быть, даже заменить операторы сравнения? Таким образом, скрипт на evil.com может обмануть нашу приятную маленькую проверку.

Комментарии:

1. Мне все еще интересно, безопасно ли «решение» номер 2 («jsonp будет вызывать функцию, только если обнаружит, что эта переменная имеет правильное значение») или ее можно взломать.

Ответ №1:

У меня в голове не укладывается…

  1. Настройте свой веб-сервер так, чтобы ограничить доступ к вашему веб-сервису для клиентов в вашей собственной сети.

  2. Реорганизуйте веб-службу, чтобы отклонять запросы от неизвестных хостов.

  3. Используйте SSL для своего веб-сервиса и требуйте аутентификации при доступе.

  4. Установите прокси-сервер между клиентами и вашей веб-службой, чтобы ограничить доступ на основе сети, адреса или домена.

Редактировать

В связи с вашими комментариями:

1 и 2 — Рефереры могут быть подделаны. Подделать IP-адрес намного сложнее.

3 — Да, и использование аутентификации с использованием SSL усложняет атаки типа «человек посередине». (У меня был соблазн сказать «невозможно», но это было бы высокомерием. 🙂

4 — Я предложил это как вариант, если у вас не было доступа к вашему веб-серверу или вы не смогли настроить его.

Но в основном это спорные вопросы, поскольку либо я неправильно понял, либо вы изменили условия вопроса.

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

Поскольку вы ожидаете, что клиенты вашего веб-сервиса будут расположены где угодно, будет работать только вариант 3.

Однако уже существуют стандартные средства ограничения доступа к веб-сервису (или его частям.)

Для каждого авторизованного клиента сгенерируйте уникальный «ключ API» и требуйте, чтобы все вызовы защищенной функциональности включали этот токен. В этом случае веб-служба отклоняет вызовы в защищенные области без действительного ключа.

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

ОТРЕДАКТИРУЙТЕ

Наконец, после повторного прочтения вашего первоначального вопроса, похоже, что это также не сработает для вас, поскольку, похоже, вы запрашиваете данные из контекста существующей веб-страницы, что означает, что вам нужно предоставить ключ API в исходном коде JavaScript.

Итак, ваша оригинальная идея может показаться вам лучшим выбором, если:

  • каждый ключ был сгенерирован с использованием неочевидного алгоритма (например, MD5 по случайным данным)
  • ключ был встроен в исходный код JavaScript и использовался для доступа к защищенным данным через AJAX
  • как только ключ был использован, он сразу же стал недействительным и не мог быть использован снова

Но (и это огромное «но»!),

  1. невозможно гарантировать, что исходный запрос страницы поступил от пользователя, а не от автоматизированного процесса, разработанного для подделки вашего сервиса.

  2. Как только данные были получены браузером, они становятся доступными для проверки любым пользователем, использующим различные инструменты мониторинга (например, firebug).

  3. Если данные затем представлены на веб-странице, их можно легко удалить (с помощью копирования / вставки).

Итак, с практической точки зрения, действительно невозможно защитить данные от перехвата и проверки с помощью используемых вами инструментов.

Комментарии:

1. 1. и 2. это будет то же самое, что проверка реферера?

2. 3. «аутентификация» = обычный вход на сайт / pw?

3. 4. как прокси-сервер может чем-то помочь? для пояснения: клиент может находиться на любом компьютере, работающем в Интернете.

4. я добавил некоторые пояснения к исходному вопросу. Особенно я не хочу быть «безопаснее», чем был бы с обычным json ajax. Ошибка Firebug или копирование / вставка не являются проблемой. Возможно, вам поможет, если вы прочтете связанную статью о CSRF.

5. И спасибо за работу, которую вы вложили в это! Даже если это на самом деле не затрагивает суть вопроса.

Ответ №2:

Швы просто решить с помощью некоторого псевдокода.

При каждом запросе выполняйте.

 if(!session['csrf-token']) {
  session['csrf-token'] = randomString();
}
  

На странице, где вы хотите получить кэшируемые данные.

 <script src="/some_cacheable_data.js?<%= session['csrf-token'] %>"></script>
  

При рендеринге javascript.

 if(params['csrf-token'] == sesssion['csrf-token']) {
  renderData();
}
  

Ответ №3:

Если данные доступны через JSONP, нет способа защитить от других третьих сторон. Единственное решение, которое я могу придумать, — это использовать канал вне границ, т. е. Прямой вызов API или своего рода секретный токен. В лучшем случае срок действия токена CSRF истекает после каждого обращения к нему, но это может привести к возможному отказу в обслуживании.

Комментарии:

1. Привет! Я так давно задавал этот вопрос, и, возможно, мой первоначальный вопрос был не очень ясен. Я добавил один «практический пример», можете ли вы проверить, находимся ли мы на одной странице?

2. упс, кажется, я повторяюсь в своих правках.. это хаотичный вопрос. надеюсь, это все еще помогает

3. хорошо, предполагая, что мы находимся на одной странице, «своего рода секретный токен», который вы предлагаете, что именно это может быть? в коде, который я предлагаю, уже есть секретный токен, приближается ли это к тому, что вы предлагаете? Также «прямой вызов API», что бы это было?

4. Прямым вызовом API будет сервер, выполняющий запрос REST на стороне сервера. Это, конечно, сведет на нет цель использования JSONP, если только у вас нет другой цели для этого, помимо предоставления доступа к вашим данным внешним доменам.

5. да. но ajax может быть отправлен только после выполнения скриптов, тогда как js может загружаться, пока страница все еще загружается. Однако я могу быть совершенно неправ в этом.

Ответ №4:

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

Не уверен насчет внезапного снижения голосов, но я проделал большую работу по обеспечению безопасности с Foursquare, Netflix и (смеется) AOL. Токен CSFR не похож на cookie.Злоумышленник не может угадать ваш токен CSRF. Который отправляется клиенту во время входа в систему или встроен в веб-страницу. Он не отправляется автоматически со всеми запросами, как файл cookie, поэтому злоумышленник не может заставить ваш браузер отправить его с тегом img или каким-либо другим странным способом. Он включен во фреймворк интерфейса ваших приложений.

Комментарии:

1. хорошо, тогда я также могу забыть о кэшировании на стороне клиента, я думаю. по крайней мере, я не могу ожидать использования обычного кэша браузера для файлов js.

2. Спасибо! Знаете ли вы какую-нибудь хорошую документацию о «повторной атаке»?

3.en.wikipedia.org/wiki/Replay_attack В принципе, кто-то, кто прослушивает, может просто воспроизвести то, что вы сказали серверу, не зная, что это на самом деле было, чтобы, возможно, получить тот же ответ. Хорошее чтение:en.wikipedia.org/wiki/Public-key_cryptography pgpi.org/doc/pgpintro

4. Это будет применяться таким же образом к обычному json?

5. Повторная атака может быть применена к вызову CSRF tocken’d JSON-p. Простого наличия переменной токена CSFR на странице, которая используется во время вызовов JSON-p и которая изменяется при каждом сеансе (или обновлении страницы), было бы достаточно, чтобы предотвратить получение кем-либо вашего JSON-p. Последние две ссылки касаются общей криптографии с открытым / закрытым ключом, фундаментальной концепции, которая используется во всех наших защищенных материалах сегодня (от HTTS до SSH) и которая также не использует ключи повторно.