Токен CSRF необходим при использовании аутентификации без сохранения состояния (= без сеанса)?

125

Нужно ли использовать защиту CSRF, если приложение использует аутентификацию без сохранения состояния (используя что-то вроде HMAC)?

Пример:

  • У нас есть одно приложение страницы ( в противном случае мы должны добавить маркер на каждой ссылке: <a href="...?token=xyz">...</a>.

  • Пользователь аутентифицируется с помощью POST /auth. При успешной аутентификации сервер вернет некоторый токен.

  • Токен будет храниться через JavaScript в некоторой переменной внутри одностраничного приложения.

  • Этот токен будет использоваться для доступа к URL с ограниченным доступом, например /admin.

  • Токен всегда будет передаваться внутри заголовков HTTP.

  • НЕТ Http-сессии и НЕТ файлов cookie.

Насколько я понимаю, не должно (?!) быть возможности использовать межсайтовые атаки, потому что браузер не будет хранить токен, и, следовательно, он не может автоматически отправить его на сервер (что произойдет при использовании файлов cookie / сессия).

Я что-то упускаю?

Бенджамин М
источник
6
Будьте осторожны с Basic Auth. Многие браузеры автоматически отправляют основные заголовки аутентификации до конца сеанса. Это может сделать базовую аутентификацию такой же уязвимой для CSRF, как аутентификацию cookie.
phylae

Ответы:

159

Я нашел информацию о CSRF + без использования файлов cookie для аутентификации:

  1. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
    «поскольку вы не полагаетесь на файлы cookie, вам не нужно защищаться от межсайтовых запросов»

  2. http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/
    "Если мы пойдем по пути файлов cookie, вам действительно нужно будет выполнить CSRF, чтобы избежать межсайтовых запросов. Это то, что мы можем забудьте при использовании JWT, как вы увидите ".
    (JWT = Json Web Token, аутентификация на основе токенов для приложений без сохранения состояния)

  3. http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services
    «Самый простой способ выполнить аутентификацию, не рискуя уязвимостью CSRF, - просто избегать использования файлов cookie для идентификации пользователя. "

  4. http://sitr.us/2011/08/26/cookies-are-bad-for-you.html
    «Самая большая проблема с CSRF заключается в том, что файлы cookie не обеспечивают абсолютно никакой защиты от этого типа атак. Если вы используете аутентификацию файлов cookie вы также должны принять дополнительные меры для защиты от CSRF. Самая основная мера предосторожности, которую вы можете предпринять, - убедиться, что ваше приложение никогда не выполняет никаких побочных эффектов в ответ на запросы GET ".

Есть еще много страниц, на которых говорится, что вам не нужна защита CSRF, если вы не используете файлы cookie для аутентификации. Конечно, вы все еще можете использовать файлы cookie для всего остального, но не храните в них что-либо подобное session_id.


Если вам нужно запомнить пользователя, есть 2 варианта:

  1. localStorage: Хранилище ключей и значений в браузере. Сохраненные данные будут доступны даже после того, как пользователь закроет окно браузера. Данные недоступны для других веб-сайтов, потому что каждый сайт получает собственное хранилище.

  2. sessionStorage: Также в хранилище данных браузера. Разница в том, что данные удаляются, когда пользователь закрывает окно браузера. Но это все равно полезно, если ваше веб-приложение состоит из нескольких страниц. Итак, вы можете сделать следующее:

    • Пользователь входит в систему, затем вы сохраняете токен в sessionStorage
    • Пользователь нажимает ссылку, которая загружает новую страницу (= настоящая ссылка, без замены содержимого javascript)
    • Вы по-прежнему можете получить доступ к токену из sessionStorage
    • Чтобы выйти из системы, вы можете либо вручную удалить токен, sessionStorageлибо подождать, пока пользователь закроет окно браузера, что очистит все сохраненные данные.

(для обоих посмотрите здесь: http://www.w3schools.com/html/html5_webstorage.asp )


Существуют ли официальные стандарты аутентификации токенов?

JWT (Json Web Token): я думаю, что это все еще черновик, но он уже используется многими людьми, и концепция выглядит простой и надежной. (IETF: http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25 )
Существуют также библиотеки для множества доступных фреймворков. Просто погуглите!

Бенджамин М
источник
37
Отличное резюме по CSRF! Замечу, что хранение ваших токенов в localStorage или sessionStorage уязвимо для XSS-атак и что данные можно просматривать с помощью скриптов на странице - поэтому, если у вас есть скомпрометированный скрипт, обслуживаемый из CDN, или если в одном из ваших JS-библиотеки, они могут украсть токен из этих мест хранения. См.: Stormpath.com/blog/… Я думаю, что наиболее безопасным подходом является сохранение токена JWT + CSRF в файле cookie, а затем размещение вычисленного JWT с токеном CSRF внутри него в заголовке запроса.
Аарон Грей
Относительно: «Самая простая мера предосторожности, которую вы можете предпринять, - убедиться, что ваше приложение никогда не выполняет никаких побочных эффектов в ответ на запросы GET». Может ли CSRF-атака подделать запрос POST?
Коста
В зависимости от серверного приложения это МОЖЕТ быть возможным. Существуют веб-фреймворки, которые используют что-то вроде http://.../someRestResource?method=POST. Таким образом, это в основном GETзапрос, но серверное приложение интерпретирует его как POSTзапрос, поскольку оно было настроено на использование methodпараметра вместо HTTP-заголовка. ...Что касается обычных веб-браузеров, они применяют политику одного и того же происхождения и будут выполнять GETзапросы только к сторонним серверам. Хотя можно было бы выполнять POSTзапросы, если веб-браузер не применяет эти веб-стандарты (ошибка, вредоносное ПО).
Benjamin M
1
Дополнение к Server Side App: По-прежнему невозможно отправить тело запроса, потому что обычные браузеры не позволяют этого. Однако, если серверное приложение позволяет method=POST, оно также может позволить body={someJson}переопределить тело запроса по умолчанию. Это действительно плохой дизайн API и крайне рискованный. Хотя, если ваше серверное приложение позволяет, http://...?method=POST&body={someJson}вам действительно стоит задуматься о том, что вы там делали, зачем и нужно ли это вообще. (Я бы сказал, что в 99,9999% случаев в этом нет необходимости). Кроме того, таким образом браузеры могут отправлять только несколько килобайт.
Benjamin M
@BenjaminM замечает, что Same Origin Policy не позволяет коду javaScript получить доступ к результату, поэтому, пока запрос «заблокирован», он фактически достигает сервера - jsbin.com/mewaxikuqo/edit?html,js,output Я тестировал это только на firefox, но вы можете открыть инструменты разработчика и увидеть, что даже если вы получите сообщение «Запрос на перекрестный запрос заблокирован», удаленный сервер действительно видит весь запрос. вот почему у вас должны быть токены или настраиваемые заголовки (а если возможно и то и другое) для всех ваших запросов POST
Йони Джа,
59

TL; DR

JWT, если он используется без файлов cookie, устраняет необходимость в токене CSRF - НО! сохраняя JWT в session / localStorage, вы раскрываете свой JWT и личность пользователя, если ваш сайт имеет XSS-уязвимость (довольно часто). Лучше добавить csrfTokenключ к JWT и сохранить JWT в файле cookie с установленными атрибутами secureи http-only.

Прочтите эту статью с хорошим описанием для получения дополнительной информации https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

Вы можете сделать эту защиту CSRF без сохранения состояния, включив xsrfToken JWT:

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "tom@andromeda.com", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

Таким образом, вам нужно будет сохранить csrfToken в localStorage / sessionStorage, а также в самом JWT (который хранится в защищенном cookie только для http). Затем для защиты csrf убедитесь, что токен csrf в JWT совпадает с отправленным заголовком csrf-token.

Скотт Юнгвирт
источник
2
Следует ли исключить использование токена csrf во время аутентификации пользователя по API?
user805981 06
3
Стоит отметить (как другие также упоминали в комментариях к исходной ссылке), что любое смягчение CSRF, которое использует а) файлы cookie, которые не предназначены только для http, или б) хранит токен CSRF в локальном хранилище, уязвимо для XSS. Это означает, что представленный подход может помочь сохранить секрет JWT от злоумышленника, использующего XSS, но злоумышленник по-прежнему сможет выполнить вредоносный запрос в вашем API, потому что он может предоставить действительный JWT (через файл cookie, спасибо браузеру) и токен CSRF (читается через внедренный JS из локального хранилища / cookie).
Йоханнес Рудольф
1
На самом деле даже токен CSRF не может защитить вас на этом уровне XSS, поскольку вы предполагаете, что злоумышленник может получить доступ к localStorage, который в настоящее время единственный способ получить доступ к нему - это иметь доступ на уровне сценария, который они могут в любом случае взглянуть на токен CSRF ,
itsnotvalid
1
Разве это не то, что говорил @JohannesRudolph? Как только вы сохраняете токен CSRF в веб-хранилище / cookie, отличном от http, вы увеличиваете свой след от XSS-атаки, потому что они доступны через JS.
adam-beck
1
Не полный эксперт здесь, но если вы все еще сталкиваетесь с XSS, как и вначале, я не уверен, что часть, которую лучше добавить ... действительно работает. Возможно, для злоумышленника немного сложнее получить токен CSRF, но в конце концов он все еще может выполнить запрос от вашего имени, даже не зная токен JWT. Это правильно? Спасибо
superjos 01