如何检查nonce是否已被使用?

时间:2017-08-14 14:53:16

标签: ruby-on-rails ruby-on-rails-3 oauth nonce

在我的Rails 3.1.5应用程序中,我使用ims-lti gem来执行第三方身份验证。要执行身份验证,必须完成三件事:

  1. 检查请求签名是否正确
  2. 检查时间戳是否太旧
  3. 检查nonce是否未被使用
  4. 前两个已完成,但我在使用随机数检查时遇到问题。我发现的大多数问题都涉及在Rails中生成nonces,而不是检查它们。

    有几个相关问题使用oauth-plugin gem来检查现时:

    Rails oauth-plugin: multiple strategies causes duplicate nonce error

    OAuth signature verification fails

    return false unless OauthNonce.remember(nonce, timestamp)
    

    不幸的是,oauth-plugin gem自2013年以来一直没有更新,并且与ims-lti gem所需的oauth gem版本不兼容。

    oauth gem似乎不支持验证nonce。

    是否有一种固定的方法可以检查nonce,无论是在原生Rails还是通过gem,或者我降级为:

    • 创建一个nonce表
    • 检查nonce是否已在表中
    • 在表格中存储随机数和时间戳
    • 循环表以删除带有过期时间戳的条目

1 个答案:

答案 0 :(得分:0)

这是我最终做的事情。

创建一个数据库表来存储nonce值:

<强> /db/migrate/<timestamp>_create_oauth_nonces.rb

class CreateOauthNonces < ActiveRecord::Migration
  def change
    create_table :oauth_nonces do |t|
      t.string :nonce
      t.timestamp :timestamp
    end
    add_index :oauth_nonces, :nonce
    add_index :oauth_nonces, :timestamp
  end
end

由于nonce是短暂的,因此在不再需要它们之后应该删除它们。 Sidekiq和Redis gems可用于异步执行nonce删除:

<强> /app/workers/oauth_nonces_worker.rb

class OauthNoncesWorker
  include Sidekiq::Worker

  def perform(nonce_id)
    OauthNonces.find(nonce_id).delete
  end
end

在会话控制器中,执行随机数处理 - 检查请求是否已过期,然后检查nonce值,如果通过,则将nonce删除队列:

<强> sessions_controller.rb

request_timestamp = DateTime.strptime(params[:oauth_timestamp], '%s')
nonce_expiry_time = 5.minutes

if request_timestamp < nonce_expiry_time.ago
    # Handle expired request here
end

nonce_exists = OauthNonces.find_by_nonce(params[:oauth_nonce])

if nonce_exists
  # Handle re-used nonce here
end

# Store the new nonce in the nonces table
nonce = OauthNonces.create!({ nonce: params[:oauth_nonce], timestamp: timestamp }, without_protection: true)

# Use Sidekiq and Redis to queue the nonce deletion
begin
  OauthNoncesWorker.perform_in(nonce_expiry_time, nonce.id)
rescue Redis::CannotConnectError
  # Okay to swallow error, since enqueuing the nonce deletion is for performance only
  # Users shouldn't be prevented from logging in just because the nonce deletion worker isn't running
end

这不是最好的解决方案,还有待改进的空间。

  • 由于nonce不需要持续超过几分钟,因此使用数据库表是过度的。最好缓存它们,并在每次登录时保存数据库请求。
  • 而不是排队每个nonce删除,而不是后台工作人员可以每分钟清除过期的nonce。