如何手动解密 Rails 5 会话 cookie?
Posted
技术标签:
【中文标题】如何手动解密 Rails 5 会话 cookie?【英文标题】:How to decrypt a Rails 5 session cookie manually? 【发布时间】:2017-05-19 08:31:45 【问题描述】:我可以访问
config.action_dispatch.encrypted_cookie_salt
config.action_dispatch.encrypted_signed_cookie_salt
secrets.secret_key_base
完整的 cookie 字符串(包括 --
)
我在 Rails 4 (Rails 4: How to decrypt rails 4 session cookie (Given the session key and secret)) 中看到了执行此操作的方法,但这些方法似乎在 Rails 5 中不起作用。
【问题讨论】:
【参考方案1】:前几天我遇到了同样的问题,发现生成的密钥长度为 64 字节(在我的 Mac 上),但 Rails 确保密钥长度为 32 字节(source)。
这对我有用:
require 'cgi'
require 'json'
require 'active_support'
def verify_and_decrypt_session_cookie(cookie, secret_key_base)
cookie = CGI::unescape(cookie)
salt = 'encrypted cookie'
signed_salt = 'signed encrypted cookie'
key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
secret = key_generator.generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len]
sign_secret = key_generator.generate_key(signed_salt)
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
encryptor.decrypt_and_verify(cookie)
end
或者没有ActiveSupport
:
require 'openssl'
require 'base64'
require 'cgi'
require 'json'
def verify_and_decrypt_session_cookie(cookie, secret_key_base)
cookie = CGI.unescape(cookie)
#################
# generate keys #
#################
encrypted_cookie_salt = 'encrypted cookie' # default: Rails.application.config.action_dispatch.encrypted_cookie_salt
encrypted_signed_cookie_salt = 'signed encrypted cookie' # default: Rails.application.config.action_dispatch.encrypted_signed_cookie_salt
iterations = 1000
key_size = 64
secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret_key_base, encrypted_cookie_salt, iterations, key_size)[0, OpenSSL::Cipher.new('aes-256-cbc').key_len]
sign_secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret_key_base, encrypted_signed_cookie_salt, iterations, key_size)
##########
# Verify #
##########
data, digest = cookie.split('--')
raise 'invalid message' unless digest == OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, sign_secret, data)
# you better use secure compare instead of `==` to prevent time based attact,
# ref: ActiveSupport::SecurityUtils.secure_compare
###########
# Decrypt #
###########
encrypted_message = Base64.strict_decode64(data)
encrypted_data, iv = encrypted_message.split('--').map|v| Base64.strict_decode64(v)
cipher = OpenSSL::Cipher.new('aes-256-cbc')
cipher.decrypt
cipher.key = secret
cipher.iv = iv
decrypted_data = cipher.update(encrypted_data)
decrypted_data << cipher.final
JSON.load(decrypted_data)
end
请随意评论要点:https://gist.github.com/mbyczkowski/34fb691b4d7a100c32148705f244d028
【讨论】:
【参考方案2】:这是@matb 答案的 Rails 5.2 变体,它处理修改后的配置、加密和序列化:
require 'cgi'
require 'active_support'
def verify_and_decrypt_session_cookie(cookie, secret_key_base = Rails.application.secret_key_base)
cookie = CGI::unescape(cookie)
salt = 'authenticated encrypted cookie'
encrypted_cookie_cipher = 'aes-256-gcm'
serializer = ActiveSupport::MessageEncryptor::NullSerializer
key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
key_len = ActiveSupport::MessageEncryptor.key_len(encrypted_cookie_cipher)
secret = key_generator.generate_key(salt, key_len)
encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: encrypted_cookie_cipher, serializer: serializer)
encryptor.decrypt_and_verify(cookie)
end
同样在https://gist.github.com/inopinatus/e523f36b468f94cf6d34410b73fef15e。
【讨论】:
以上是关于如何手动解密 Rails 5 会话 cookie?的主要内容,如果未能解决你的问题,请参考以下文章