Как включить 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!