Одностраничное приложение и CSRF-токен - PullRequest
0 голосов
/ 03 мая 2018

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

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

class ApplicationController < ActionController::Base

  after_action :set_csrf_cookie

  def set_csrf_cookie
    cookies["X-CSRF-Token"] = form_authenticity_token
  end

end

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

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

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

ПРОЯСНИТЬ

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

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

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

Ответы [ 4 ]

0 голосов
/ 14 июня 2018

Я просто отвечу на вопрос. Полная информация объясняется в этой статье: 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":'equivalent@eq8.eu", "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 использует только заголовок Authentication для аутентификации. Тогда вам не нужна защита от CSRF.

Нет файлов cookie сеанса, нет проблем CSRF!

* 1 028 * Пример:
curl POST  https://api.my-app.com/login.json  -d "{"email":'equivalent@eq8.eu", "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"

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

0 голосов
/ 07 мая 2018

Я не знаю, с какой именно проблемой вы столкнулись. Но если у вас возникают проблемы с CSRF в новых версиях 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. диалог подтверждения принудительного выполнения различных действий;
  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 вы получаете класс 'Rails' в js и можете использовать функции.

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

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

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

config/initializers/cors.rb

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

0 голосов
/ 08 мая 2018

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

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

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

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

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

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

Вам нужна защита CSRF с помощью API?

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

0 голосов
/ 03 мая 2018

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

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

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