我正在尝试保护Sinatra API。
我正在使用ruby-jwt
来创建JWT,但我不确切地知道要用它来签名。
我正在尝试使用用户的BCrypt password_digest
,但每次调用password_digest
时它都会发生变化,当我去验证时,签名无效。
答案 0 :(得分:3)
使用任何类型的应用程序密钥,而不是用户的bcrypt密码摘要。
例如,使用dot env gem和.env文件,条目如下:
JWT_KEY=YOURSIGNINGKEYGOESHERE
我个人使用简单的随机十六进制字符串生成密钥:
SecureRandom.hex(64)
十六进制字符串只包含0-9和a-f,因此该字符串是URL安全的。
答案 1 :(得分:1)
根据wikipedia,密码学中使用的密钥基本上只是一个打开锁的密钥。密钥应该是一致且可靠的,但不容易复制,就像您在家中使用的密钥一样。
如this answer所述,秘密密钥应随机生成。但是,您仍希望保留密钥以在整个应用程序中使用。通过使用来自bcrypt的密码摘要,您实际上使用的是从基本密钥(密码)派生的散列密钥。因为散列是随机的,所以这不是可靠的密钥,正如你所说的那样。
使用SecureRandom.hex(64)
的上一个答案是创建初始基本应用程序密钥的好方法。但是,在生产系统中,您应该将其作为配置变量并将其存储,以便在应用程序的多次运行中保持一致使用(例如,在服务器重新启动后,您不应使所有用户的JWT无效)或跨多个分布式服务器This article给出了一个从rails环境变量中提取密钥的示例。
答案 2 :(得分:0)
对于RS256公钥和私钥策略,您可以使用Ruby OpenSSL lib:
生成密钥:
key = OpenSSL::PKey::RSA.new 2048
open 'private_key.pem', 'w' do |io| io.write key.to_pem end
open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end
从.pem文件加载密钥以签名令牌:
priv_key = OpenSSL::PKey::RSA.new File.read 'private_key.pem'
token = JWT.encode payload, priv_key, 'RS256'
从.pem文件中加载密钥以验证令牌(为此创建中间件):
begin
# env.fetch gets http header
bearer = env.fetch('HTTP_AUTHORIZATION').slice(7..-1)
pub_key = OpenSSL::PKey::RSA.new File.read 'public_key.pem'
payload = JWT.decode bearer, pub_key, true, { algorithm: 'RS256'}
# access your payload here
@app.call env
rescue JWT::DecodeError
[401, { 'Content-Type' => 'text/plain' }, ['A token must be passed.']]
rescue JWT::ExpiredSignature
[403, { 'Content-Type' => 'text/plain' }, ['The token has expired.']]
rescue JWT::InvalidIssuerError
[403, { 'Content-Type' => 'text/plain' }, ['The token does not have a valid issuer.']]
rescue JWT::InvalidIatError
[403, { 'Content-Type' => 'text/plain' }, ['The token does not have a valid "issued at" time.']]
end