2017-04-10 18 views
2

我有一个使用仅限http的cookie进行身份验证的Rails API,因此我需要CSRF保护。据我所知,Rails社区似乎更喜欢将jwt auth令牌存储在本地存储中,而不是cookie中。这避免了对CSRF的需求,但是将您暴露给XSS,这就是我们选择使用cookie + csrf的原因。如何在Rails 5 API模式下启用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能够使用这种方案?

回答

4

我意识到这是一个超越问题的例子。我真的不需要Rails的伪造保护来为我做任何事情,或者检查session的值,因为我的令牌的价值已经是cookie了。以下是我如何解决它:

首先,基础控制器设置csrf cookie。如果有退出或任何公共端点,则会跳过此选项。

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 

希望这可以帮助其他人试图使用CSRF +饼干在Rails 5 API:

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令牌继承!