Ruby on rails 这段(小)代码是否正确地防止了API密钥定时攻击?(RoR)

Ruby on rails 这段(小)代码是否正确地防止了API密钥定时攻击?(RoR),ruby-on-rails,api,Ruby On Rails,Api,我正在为我正在创建的API项目实施API密钥身份验证/授权。我正在使用authenticate\u或\u request\u和\u http\u token方法调用,并防止定时攻击。我第一次读到有关定时攻击的内容,并尝试在我的ApplicationController中实现该安全防护。我相信我已经正确地完成了该机制,但希望得到确认。下面是代码片段 before_action :authenticate_request def authenticate_request authenticat

我正在为我正在创建的API项目实施API密钥身份验证/授权。我正在使用
authenticate\u或\u request\u和\u http\u token
方法调用,并防止定时攻击。我第一次读到有关定时攻击的内容,并尝试在我的
ApplicationController
中实现该安全防护。我相信我已经正确地完成了该机制,但希望得到确认。下面是代码片段

before_action :authenticate_request

def authenticate_request
  authenticate_or_request_with_http_token do |token, options|
    api_key = ApiKey.find_by(access_token: token)
    secret_key = ApiKey.find(api_key.id).secret_key
    api_key.present? && (api_key.active != false) && secure_compare_with_hashing(api_key.secret_key, secret_key)
  end
end

def secure_compare_with_hashing(key1, key2)
  ActiveSupport::SecurityUtils.secure_compare(key1, key2)
end
基本上,我是1)。通过头中提交的令牌查找Api密钥,2)。然后,我使用api_密钥的id来检索密钥。3). 我正在比较两个值的密钥以进行时间常数比较

如果我没有弄错的话,我相信这应该满足成功缓解定时攻击的要求。我说的对吗

======更新======

对于上下文,我使用此资源来解决计时错误。这里有一小段引用自在线图书

我们实现API密钥的方式容易受到定时攻击。这就是为什么许多web API都带有访问密钥和密钥。在对密钥进行安全比较之前,可以使用访问密钥在数据库中查找记录

为了以安全的方式检查API密钥是否有效,我们需要在不使用实际令牌的情况下检索数据库记录。实际上,像ApiKey.where(key:'abc')这样的SQL查询容易受到定时攻击

为了避免这种情况,我们可以要求客户提供另一种查找记录的方法,例如通过发送密钥id。我们最终会收到api_key=1:abc而不是api_key=abc,其中1是api密钥id

对于实际应用程序,我们应该创建一个新字段来保存访问密钥,而不是使用id

下面是我试图修改的代码

module Authentication
  include ActiveSupport::SecurityUtils
  # Hidden Code

  included # Hidden Code

  private

  def validate_auth_scheme # Hidden Code
  def unauthorized! # Hidden Code
  def authorization_request # Hidden Code

  def credentials
    @credentials ||= Hash[authorization_request.scan(/(\w+)[:=] ?"?([\w|:]+)"?/)]
  end

  def api_key
    @api_key ||= compute_api_key
  end

  def compute_api_key
    return nil if credentials['api_key'].blank?

    id, key = credentials['api_key'].split(':')
    api_key = id && key && ApiKey.activated.find_by(id: id)

    return api_key if api_key && secure_compare_with_hashing(api_key.key, key)
  end

  def secure_compare_with_hashing(a, b)
    secure_compare(Digest::SHA1.hexdigest(a), Digest::SHA1.hexdigest(b))
  end

end
我的代码是否没有正确遵循此过程?忽略problm的情况,即我的代码不返回密钥,比较secret_密钥是否有意义

比如说,

api_key = ApiKey.find_by(access_token: token) #Timing attack :(
我使用找到的api_密钥获取密钥

secret_key = ApiKey.find(api_key.id).secret_key
避开了定时攻击

secure_compare_with_hashing(api_key.secret_key, secret_key)

secure\u compare
通过将字符串转换为同样长的散列来防止定时攻击,所以这应该没问题

但是,我想知道以前的代码做了什么

此代码段是否没有两次获取相同的
ApiKey
?当令牌不存在时,您的实现中也存在一个bug

api\u key=ApiKey.find\u by(访问令牌:令牌)
secret_key=ApiKey.find(api_key.id).secret_key#如果令牌不存在,则此操作将崩溃
secure_compare_与_hashing(api_key.secret_key,secret_key)#总是正确的,不是吗?
此外,这将有助于提前返回。虽然不可能猜出整个密码,但如果api_密钥存在,仍然可以获取信息

api_key.present?&(api_key.active!=false)

##编辑

与您提供的教程相比,您确实做了不应该做的事情

def认证请求
使用_http _tokendo | token,选项验证_或_请求|

api_key=ApiKey.find_by(access_token:token)#嘿,克里斯蒂安,谢谢你回答我的问题,你能看看我的更新吗?除了找不到或禁用密钥的bug之外,我是否绕过了定时攻击?我抓取令牌中提供的密钥,查找密钥,然后比较密钥。我注意到安全比较总是返回true,这在我正在改编的示例中很奇怪。作为另一个更新,本质上我想在书中完美地总结这一点。您基本上只需对书中的片段进行c&p,因此是的,这似乎不易受到定时攻击。如果回答了你的问题,请考虑接受答案。更新我的初步答案。