如何手动解密Rails 5会话cookie?

我有权访问

  • config.action_dispatch.encrypted_cookie_salt
  • config.action_dispatch.encrypted_signed_cookie_salt
  • secrets.secret_key_base
  • 完整的cookie字符串(包括--

我在Rails 4中看到了这样做的方法( Rails 4:如何解密rails 4会话cookie(给定会话密钥和秘密) ),但这些似乎在Rails 5中不起作用。

我前几天遇到了同样的问题并且发现生成的秘密长度为64字节(在我的Mac上),但是Rails确保密钥长度为32字节( 源 )。

这对我有用:

 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::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

这是@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 。