2

我正在为我的 ruby​​ 应用程序创建一个 API,它基于 HTTP Digest Authentication 对用户进行身份验证。我决定使用 Grape API 库,因为它可以在 ruby​​ 中创建 API 清洁器。Grape 文档指出您可以使用摘要式身份验证,例如:

http_digest({ :realm => 'Test Api', :opaque => 'app secret' }) do |username|
  # lookup the user's password here
  { 'user1' => 'password1' }[username]
end

上面的葡萄实现是一个包装器Rack::Auth::Digest::MD5

现在,为了安全起见,我读到,从 RFC 2617 开始,您不需要将密码作为纯文本存储在数据库中,您可以存储用户名的 MD5 摘要:realm:password 并针对它进行身份验证,因此我创建了一个 DataMapper 模型:

class Key
  include DataMapper::Resource

  property :id,              Serial

  property :username,        String
  property :password,        String

  property :active,          Boolean, :default => true
  property :created_at,      DateTime, :default => DateTime.now
  property :updated_at,      DateTime
end

现在有了我提供的东西,我不知道如何将这两者联系起来并使其工作。

4

1 回答 1

3

不幸的是,Rack::Auth::Digest::MD5在服务器端需要一个明文密码。

Grape 示例代码显示了对密码的硬编码查找。

你可以{ 'user1' => 'password1' }[username]

Key.first( :username => username ).password

前提是您在课堂上存储了明文密码。Key我想您可以存储这些可逆加密的内容,尽管除非您为密钥管理构建相对复杂/昂贵的方案,否则这不会增加太多安全性。

不确定是否有办法让您存储散列密码。MD5 不是最安全的散列选择(尽管总比没有好!)。如果安全性是您的 API 的一个重要问题,您将希望超越摘要式身份验证 - 例如,使用 https 会有所帮助。

编辑:在讨论中反复讨论之后,Grape 示例的以下变体确实允许您存储 MD5 密码:

auth :http_digest, { :realm => { :realm => 'Llama', :passwords_hashed => true, :opaque => "7302c32d39bbacb5ed0ace096723fd" } } do |username|
  Digest::MD5.hexdigest( 'fred:Llama:654321' )
end

该示例给出了一个硬编码的用户名:'fred',密码:'654321' 响应。所以我认为你的目标代码是这样的:

auth :http_digest, { :realm => { :realm => 'Llama', :passwords_hashed => true, :opaque => "7302c32d39bbacb5ed0ace096723fd" } } do |username|
  k = Key.first( :username => username )
  k ? k.password : nil
end

并将结果存储Digest::MD5.hexdigest( "#{username}:#{realm}:#{password}" )在每个用户的密码属性中。

:realm注意带有两次的双级哈希。这有点hacky,但至少您不必编写自己的中间件,Grape 仍在处理它。这不是Grape 的文档功能或测试覆盖,因此在未来的版本中可能无法使用。

于 2013-04-05T08:20:56.467 回答