如何在 Rails 5 API 模式下启用 CSRF
How to enable CSRF in Rails 5 API mode
我有一个 Rails API 使用 http-only cookie 进行身份验证,因此我需要 CSRF 保护。据我所知,Rails 社区似乎更喜欢将 jwt 身份验证令牌存储在本地存储中而不是 cookie 中。这避免了对 CSRF 的需要,但将您暴露给 XSS,这就是我们选择使用 cookies + 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
header 中。到目前为止一切看起来都很好。
但是,verified_request?
方法 returns 为 false,因此 handle_unverified_request
被调用。单步执行 Rails 代码,我看到我的令牌出现在 request.x_csrf_token
中,但是当根据 session
检查令牌时,令牌似乎无法通过验证。我想知道的一件事是,我是否需要启用某些功能才能使 session
正常工作,据我所知,session 管理在 API 模式下默认未启用.但是,如果是这种情况,我希望访问 session
object 的尝试会失败,但他们不会,所以我不确定。
是我操作有误,还是需要开启其他中间件?或者我是否需要完全不同的方法来启用此方案的 CSRF?
我意识到这是一个想多了的问题。我真的不需要 Rails 的伪造保护来为我做任何事情,或者根据 session
检查值,因为我的令牌的值已经是一个 cookie。这是我解决它的方法:
首先,基础控制器设置csrf cookie。对于注销或任何 public 端点,如果有的话,这将被跳过。
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
然后我经过身份验证的端点继承自检查身份验证令牌和 csrf 令牌的 AuthenticatedController
:
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
希望这对尝试在 Rails 5 API!
中使用 CSRF + cookie 的其他人有所帮助
我有一个 Rails API 使用 http-only cookie 进行身份验证,因此我需要 CSRF 保护。据我所知,Rails 社区似乎更喜欢将 jwt 身份验证令牌存储在本地存储中而不是 cookie 中。这避免了对 CSRF 的需要,但将您暴露给 XSS,这就是我们选择使用 cookies + 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
header 中。到目前为止一切看起来都很好。
但是,verified_request?
方法 returns 为 false,因此 handle_unverified_request
被调用。单步执行 Rails 代码,我看到我的令牌出现在 request.x_csrf_token
中,但是当根据 session
检查令牌时,令牌似乎无法通过验证。我想知道的一件事是,我是否需要启用某些功能才能使 session
正常工作,据我所知,session 管理在 API 模式下默认未启用.但是,如果是这种情况,我希望访问 session
object 的尝试会失败,但他们不会,所以我不确定。
是我操作有误,还是需要开启其他中间件?或者我是否需要完全不同的方法来启用此方案的 CSRF?
我意识到这是一个想多了的问题。我真的不需要 Rails 的伪造保护来为我做任何事情,或者根据 session
检查值,因为我的令牌的值已经是一个 cookie。这是我解决它的方法:
首先,基础控制器设置csrf cookie。对于注销或任何 public 端点,如果有的话,这将被跳过。
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
然后我经过身份验证的端点继承自检查身份验证令牌和 csrf 令牌的 AuthenticatedController
:
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
希望这对尝试在 Rails 5 API!
中使用 CSRF + cookie 的其他人有所帮助