如何签署JWT?
How to sign JWT?
我正在尝试保护 Sinatra API。
我正在使用 ruby-jwt
创建 JWT,但我不知道用什么来签名。
我正在尝试使用用户的 BCrypt password_digest
,但每次调用 password_digest
它都会发生变化,导致签名在我去验证时无效。
使用任何类型的应用程序密钥,而不是用户的 bcrypt 密码摘要。
例如,使用点环境 gem 和一个 .env 文件,其中包含一个条目,例如:
JWT_KEY=YOURSIGNINGKEYGOESHERE
我使用一个简单的随机十六进制字符串亲自生成了一个密钥:
SecureRandom.hex(64)
十六进制字符串仅包含 0-9 和 a-f,因此该字符串 URL 安全。
根据wikipedia,密码学中使用的密钥基本上就是一把开锁的钥匙。钥匙应该是一致的和可靠的,但不容易复制,就像你在家里使用的钥匙一样。
如所述,密钥应该是随机生成的。但是,您仍然希望保留密钥以便在整个应用程序中使用。通过使用来自 bcrypt 的密码摘要,您实际上是在使用从基本密钥(密码)派生的散列密钥。因为散列是随机的,所以正如您所说,这不是一个可靠的密钥。
之前使用 SecureRandom.hex(64)
的回答是创建初始基础应用程序密钥的好方法。但是,在生产系统中,您应该将其作为配置变量并将其存储起来,以便在您的应用程序的多次运行中一致使用(例如,在服务器重新启动后,您不应该使所有用户的 JWT 失效)或在多个分布式服务器。 This article 给出了从 rails.
的环境变量中提取密钥的示例
对于 RS256 public 和私钥策略,您可以使用 Ruby OpenSSL 库:
正在生成密钥:
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::ExpiredSignature
[403, { 'Content-Type' => 'text/plain' }, ['The token has expired.']]
rescue JWT::DecodeError
[401, { 'Content-Type' => 'text/plain' }, ['A token must be passed.']]
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
要在 .env
中使用 RSA 密钥而不是加载文件,您需要使用 gem 'dotenv'
并使用换行符将密钥作为单行变量导入 '\n'
.查看此 了解如何操作。示例:
PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nmineminemineminemine\nmineminemineminemine\nmineminemine...\n-----END PUBLIC KEY-----\n"
作为.env
PUBLIC_KEY
变量,加载key会变成这样:
key = OpenSSL::PKey::RSA.new ENV['PUBLIC_KEY']
我正在尝试保护 Sinatra API。
我正在使用 ruby-jwt
创建 JWT,但我不知道用什么来签名。
我正在尝试使用用户的 BCrypt password_digest
,但每次调用 password_digest
它都会发生变化,导致签名在我去验证时无效。
使用任何类型的应用程序密钥,而不是用户的 bcrypt 密码摘要。
例如,使用点环境 gem 和一个 .env 文件,其中包含一个条目,例如:
JWT_KEY=YOURSIGNINGKEYGOESHERE
我使用一个简单的随机十六进制字符串亲自生成了一个密钥:
SecureRandom.hex(64)
十六进制字符串仅包含 0-9 和 a-f,因此该字符串 URL 安全。
根据wikipedia,密码学中使用的密钥基本上就是一把开锁的钥匙。钥匙应该是一致的和可靠的,但不容易复制,就像你在家里使用的钥匙一样。
如
之前使用 SecureRandom.hex(64)
的回答是创建初始基础应用程序密钥的好方法。但是,在生产系统中,您应该将其作为配置变量并将其存储起来,以便在您的应用程序的多次运行中一致使用(例如,在服务器重新启动后,您不应该使所有用户的 JWT 失效)或在多个分布式服务器。 This article 给出了从 rails.
对于 RS256 public 和私钥策略,您可以使用 Ruby OpenSSL 库:
正在生成密钥:
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::ExpiredSignature
[403, { 'Content-Type' => 'text/plain' }, ['The token has expired.']]
rescue JWT::DecodeError
[401, { 'Content-Type' => 'text/plain' }, ['A token must be passed.']]
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
要在 .env
中使用 RSA 密钥而不是加载文件,您需要使用 gem 'dotenv'
并使用换行符将密钥作为单行变量导入 '\n'
.查看此
PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nmineminemineminemine\nmineminemineminemine\nmineminemine...\n-----END PUBLIC KEY-----\n"
作为.env
PUBLIC_KEY
变量,加载key会变成这样:
key = OpenSSL::PKey::RSA.new ENV['PUBLIC_KEY']