Как реализовать защиту csrf для междоменных запросов
У меня есть два веб-приложения: один для веб-интерфейса в AngularJS и один для веб-сервисов REST на Java. Оба они развертываются в отдельных доменах.
Приложения используют cookie для аутентификации. Всякий раз, когда пользователь вводит правильное имя пользователя и пароль, сервер возвращает только HTTP файл, содержащий только токен, и этот файл cookie передается по всем запросам. Я включил CORS в обоих приложениях, поэтому cookie сеанса работает правильно.
Теперь я пытаюсь добавить для этого защиту CSRF. Я пытался использовать файл csrf cookie, где на сервере будет отправлять cookie csrf (а не httponly) как часть ответа REST, и пользовательский интерфейс будет считывать значение из файла cookie и передавать его в заголовке токена csrf для других вызовов REST.
Проблема с этим подходом, с которым я сталкиваюсь, заключается в том, что, поскольку сервер находится в другом домене, я не могу прочитать cookie, используя $cookies в AngularJs. Есть ли способ прочитать значение этого файла cookie?
Если нет, тогда я могу реализовать CSRF каким-то другим способом?
Я также попытался реализовать создание csrf файла cookie в веб-интерфейсе пользователя в браузере, но браузер не отправляет файл cookie в веб-службу как в своем другом домене.
Итак, мой вопрос заключается в том, как реализовать защиту csrf для такого рода ситуаций?
Ответы
Ответ 1
Вы были на правильном пути с этим:
Я также попытался реализовать создание csrf файла cookie в веб-интерфейсе пользователя в браузере, но браузер не отправляет файл cookie в веб-службу как в своем другом домене.
CSRF файл cookie не предназначен для отправки на сервер, он предназначен для чтения клиентом и затем предоставляется в пользовательском заголовке HTTP-запроса. Кованные запросы GET (сгенерированные тегами HTML, такие как <img src="">
) из других доменов не могут устанавливать пользовательские заголовки, так что вы утверждаете, что запрос поступает от клиента javascript в вашем домене.
Вот как вы можете реализовать идею, над которой работаете, представьте, что у вас есть api.domain.com
и ui.domain.com
:
1) Пользователь загружает клиента Angular из ui.domain.com
2) Пользовательская информация аутентификации пользователей от Angular клиента до api.domain.com
2) Ответ Север отвечает кукией аутентификации HttpOnly
, называемой authCookie
, и настраиваемым заголовком, например. X-Auth-Cookie
, где значение этого заголовка является уникальным значением, которое связано с сеансом, идентифицированным с помощью authCookie
3) Клиент Angular считывает значение заголовка X-Auth-Cookie
и сохраняет это значение в cookie XSRF-TOKEN
в своем домене, ui.domain.com
-
Итак, теперь у вас есть:
-
XSRF-TOKEN
cookie on ui.domain.com
-
authCookie
cookie on api.domain.com
4) Пользователь делает запрос защищенного ресурса на api.domain.com
. Браузер автоматически предоставит значение authCookie
, а Angular автоматически отправит заголовок X-XSRF-TOKEN
и отправит значение, которое оно считывает из XSRF-TOKEN
cookie
5) Ваш сервер утверждает, что значение X-XSRF-TOKEN
связано с тем же сеансом, который идентифицируется значением authCookie
Надеюсь, это поможет! Я также написал об аутентификации токена для Angular, Аутентификация на основе токенов для одиночных страниц (SPA) (Отказ от ответственности: я работаю в Stormpath)
Ответ 2
У Angularjs есть встроенная поддержка CSRF, но, к сожалению, она не работает с перекрестным доменом, поэтому вам нужно создавать свои собственные.
Мне удалось заставить его работать, сначала вернув случайный токен в заголовках и куки файлах по первому запросу. Чтобы прочитать заголовок, вам нужно добавить его в Access-Control-Expose-Headers
. Затем это добавляется ко всем сообщениям
$http.get('url').
success(function(data, status, headers) {
$http.defaults.headers.post['X-XSRF-TOKEN'] = headers('XSRF-TOKEN');
});
Затем на сервере вы можете сравнить значение cookie со значением в заголовке, чтобы убедиться, что они одинаковы.
Ответ 3
$http docs: Angular предоставляет механизм для борьбы с XSRF. При выполнении запросов XHR, но не будет установлен для междоменных запросов.
Это небольшая библиотека, которая может помочь вам https://github.com/pasupulaphani/angular-csrf-cross-domain