Как реализовать защиту 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