Одностраничное приложение и токен CSRF

Мне нужно использовать одностраничное приложение (React, Ember, Angular, мне все равно) с механизмом защиты Rails CSRF.

Мне интересно, нужно ли мне создать токен evey в ApplicationController следующим образом:

 class ApplicationController < ActionController::Base after_action :set_csrf_cookie def set_csrf_cookie cookies["X-CSRF-Token"] = form_authenticity_token end end 

или я могу просто создать токен один раз .

За сеанс или за (не-GET) запрос?

Я думаю, что токен остается в силе до тех пор, пока сессия не будет действительна, правильно?

CLARIFY :

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

Поэтому в моей ситуации, если я создаю новый токен для каждого after_action предыдущий CSRF-токен по-прежнему хорош для этого сеанса. Итак, как сделать недействительным предыдущий токен? Я должен?

Потому что, только если я недействителен, это имеет смысл, верно?

Если вы отправляетесь в SPA-приложение, вы чаще всего используете Rails только как API. Маркер CSRF был разработан для рендеринга сервера … не SPA. В SPA вы уже используете токен во время аутентификации, поэтому не нужно использовать другой токен для CSRF. CSRF был разработан как защита для межсайтовых вызовов, но сам API разработан таким образом, что он позволяет запрашивать откуда угодно, пока они не будут аутентифицированы.

Просто отключите его для вашего API, и все. Я бы пошел с некоторым пространством имен API и настроил BaseController , который будет наследоваться для всех controllerов API. Там вы должны установить protect_from_forgery :

 class API::BaseController < ApplicationController protect_from_forgery with: :null_session end 

Клиентская сторона (SPA)

Вам нужно только захватить токен CSRF один раз за сеанс . Вы можете удерживать его в браузере и отправлять его на каждый (не-GET) запрос.

Rails будет генерировать новый токен CSRF для каждого запроса, но он примет любой сгенерированный токен из этого сеанса. На самом деле, это просто маскирование одного токена с использованием одноразового кода для каждого запроса, чтобы защитить от атаки SSL BREACH. Подробнее см. На странице https://stackoverflow.com/a/49783739/2016618 . Вам не нужно отслеживать / хранить эти токены.

Серверная сторона

Я настоятельно рекомендую использовать директиву protect_from_forgery Rails, а не кодировать токен CSRF в заголовке самостоятельно. Он будет генерировать другой маскированный токен для каждого запроса.

Вы можете, конечно, воспроизвести это самостоятельно, не так много кода, но я не понимаю, зачем вам это нужно.

Вам нужна CSRF-защита с API?

Да! Если вы проверяете подлинность с помощью файла cookie, вам нужна защита CSRF. Это связано с тем, что cookies отправляются с каждым запросом, поэтому вредоносный веб-сайт может отправлять запрос POST на ваш сайт и выполнять запросы от имени зарегистрированного пользователя. Маркер CSRF предотвращает это, потому что вредоносный сайт не будет знать токен CSRF.

Я не знаю, в какой именно проблеме вы столкнулись. Но если вы получаете проблемы CSRF в версиях New Rails и должны включать токены Rails CSRF в запросах ajax, вы можете выполнить следующие шаги.

Недавно я использовал приложение Rails 5.1.

При использовании вызовов ajax для извлечения некоторых данных из API-интерфейсов я получал проблемы с токеном CSRF:

 'WARNING: Can't verify CSRF token authenticity rails' 

Причина была

Rails 5.1 удалила поддержку jquery и jquery_ujs по умолчанию и добавила

 //= require rails-ujs in application.js 

Он выполняет следующие действия:

  1. диалоговые windows подтверждения действий для различных действий;
  2. делать запросы без GET из гиперссылок;
  3. создавать формы или гиперссылки, передавать данные асинхронно с Ajax;
  4. кнопки отправки автоматически отключаются при отправке формы для предотвращения двойного щелчка. (от: https://github.com/rails/rails-ujs/tree/master )

Но он не включает токен csrf для запроса ajax по умолчанию. Остерегайтесь этого. Мы должны явно передать это так:

 $( document ).ready(function() { $.ajaxSetup({ headers: { 'X-CSRF-Token': Rails.csrfToken() } }); ---- ---- }); 

Обратите внимание, что в версии Rails 5.1 вы получаете class Rails в js и можете использовать функции.

Обновление. Если вы используете сервер Rails и другие интерфейсы, вы действительно не хотите использовать Rails, предоставленные жетоны CSRF. Потому что на самом деле это не имеет значения, какой бэкэнд-сервис вы используете.

Если ваша цель – заблокировать CSRF, вам необходимо настроить CORS на бэкэнд, то есть на ваш Rails-сервер. Rails теперь предоставляет отдельный файл в инициализаторе для этого. Вы можете указать, какие сайты могут отправлять запросы ajax на ваш сервер.

Редактировать здесь:

 config/initializers/cors.rb 

Если вы хотите аутентификации, используйте базовый auth, токен auth или JWT

Я просто отвечу на вопрос. Полная информация приведена в этой статье: https://blog.eq8.eu/article/rails-api-authentication-with-spa-csrf-tokens.html

Данный Rails устанавливает cookie для SPA

Точки CSRF действительны в течение всего времени сеанса. Поэтому да, это нормально, чтобы сгенерировать один токен CSRF на время сеанса после входа в систему.

 class LoginController < ApplicationController def create if user_password_match # .... cookie[:my_csrf_token]= form_authenticity_token end end end 

или вы можете обновить cookie так же, как вы предлагаете

 class ApplicationController < ActionController::Base after_action :set_csrf_cookie def set_csrf_cookie cookies["my_csrf_token"] = form_authenticity_token end end 

Вашему SPA просто нужно прочитать файл cookie и установить его как заголовок.

Оба одинаково справедливы

или Вы можете просто указать токен CSRF в качестве ответа на вход, и SPA сохранит его где-нибудь и будет использовать его в заголовке X-CSRF-Token :

 curl POST https://api.my-app.com/login.json -d "{"email":'[email protected]", "password":"Hello"}" -H 'ContentType: application/json' # Cookie with session_id was set # response: { "login": "ok", "csrf": 'yyyyyyyyy" } # next request curl POST https://api.my-app.com/transfer_my_money -d "{"to_user_id:":"1234"}" -H "ContentType: application/json" -H "X-CSRF-Token: yyyyyyyyy" 

Данный Rails принимает только аутентификацию заголовка

если вы не используете cookie для отправки session_id, поэтому ваш API использует только заголовок аутентификации для аутентификации. Тогда вам не нужна защита CSRF.

Нет сеанса cookie нет проблем CSRF!

Пример:

 curl POST https://api.my-app.com/login.json -d "{"email":'[email protected]", "password":"Hello"}" -H 'ContentType: application/json' # No cookie/session is set # response: { "login": "ok", "jwt": "xxxxxxxxxxx.xxxxxxxx.xxxxx" } # Next Request: curl POST https://api.my-app.com/transfer_my_money -d "{"to_user_id:":"1234"}" -H "ContentType: application/json" -H "Authentication: Bearer xxxxxxxxxxx.xxxxxxxx.xxxxx" 

Еще раз, это происходит только тогда, когда вы не используете cookies для идентификации пользователя! Таким образом, CSRF не является проблемой в этом случае, но вы по-прежнему защищаете от атаки Cross-Site scripting, убедитесь, что ваша связь - это только HTTP, и т. Д. ...

  • Создание страниц главной страницы для объектов, как их связать и какой области боба выбрать
  • Почему после выхода из системы кнопка «Назад» на странице отображает содержимое предыдущей страницы?
  • Как аннулировать сеанс пользователя, когда он дважды регистрируется с одинаковыми учетными данными
  • Как обмениваться сеансами с Socket.IO 1.x и Express 4.x?
  • Сохранение сеанса ASP.NET Open / Alive
  • Как использовать сеанс на страницах JSP для получения информации?
  • Классический ASP: несколько ASPSESSIONID в файлах cookie
  • «session» не определен при использовании express / redis для хранилища сеансов
  • HttpContext.Current.Session имеет значение null в файле Ashx
  • socket.io и сеанс?
  • socket.io и выразить 4 сеанса
  • Давайте будем гением компьютера.