Как включить CSRF в режиме Rails 5 API

У меня есть Rails API, который аутентифицирован с помощью cookie только для http, и поэтому мне требуется защита CSRF. Из того, что я могу сказать, сообщество Rails, похоже, предпочитает хранить токены jwt auth в локальном хранилище, а не в cookie. Это избавляет от необходимости использовать CSRF, но предоставляет XSS, поэтому мы решили использовать куки + csrf.

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

module V1
  class ApplicationController < ::ApplicationController
    include Concerns::Authentication
    include ActionController::RequestForgeryProtection
    protect_from_forgery

    protected

    def handle_unverified_request
      raise 'Invalid CSRF token'
    end

    after_action :set_csrf_cookie

    def set_csrf_cookie
      if current_user 
        cookies['X-CSRF-Token'] = form_authenticity_token
      end
    end
  end
end

На стороне клиента я вижу, что токен возвращается в cookie. Когда я делаю запрос, я также вижу, что токен присутствует в X-CSRF-Token заголовок. Пока все выглядит хорошо.

Тем не менее verified_request? метод возвращает false, поэтому handle_unverified_request вызывается. Проходя через код Rails, я вижу, что мой токен присутствует в request.x_csrf_token, но токен не проходит проверку при проверке по session, Мне вот интересно, нужно ли мне что-то включить, чтобы получить session работать правильно, так как я понимаю, что управление сессиями не включено, по умолчанию в режиме API. Однако, если бы это было так, я бы ожидал попыток получить доступ к session объект взорвать, а они нет, так что я не уверен.

Я сделал ошибку, или есть какое-то другое промежуточное программное обеспечение, которое мне нужно включить? Или мне вообще нужен другой подход, чтобы включить CSRF с этой схемой?

1 ответ

Решение

Я понимаю, что это был случай переосмысления проблемы. Мне действительно не нужна защита от подделок Rails, чтобы что-то сделать для меня или проверить значение по sessionпотому что значение моего токена уже является cookie. Вот как я это решил:

Во-первых, базовый контроллер устанавливает cookie-файл csrf. Это будет пропущено для выхода из системы или любых общедоступных конечных точек, если таковые были.

module V1
  class ApplicationController < ::ApplicationController
    include Concerns::Authentication
    include ActionController::RequestForgeryProtection

    after_action :set_csrf_cookie

    protected

    def set_csrf_cookie
      if current_user 
        cookies['X-CSRF-Token'] = form_authenticity_token
      end
    end
  end
end

Тогда мои аутентифицированные конечные точки наследуются от AuthenticatedController который проверяет токен аутентификации и токен csrf:

module V1
  class AuthenticatedController < ApplicationController
    before_action :authenticate!

    def authenticate!
      raise AuthenticationRequired unless current_user && csrf_token_valid?
    end

    rescue_from AuthenticationRequired do |e|
      render json: { message: 'Authentication Required', code: :authentication_required }, status: 403
    end

    rescue_from AuthTokenExpired do |e|
      render json: { message: 'Session Expired', code: :session_expired }, status: 403
    end

    private

    def csrf_token_valid?
      Rails.env != 'production' || request.headers['X-CSRF-Token'] === cookies['X-CSRF-Token']
    end
  end
end

Надеюсь, это поможет кому-то другому, пытающемуся использовать файлы cookie CSRF + в API Rails 5!

Другие вопросы по тегам