ruby-on-rails - rails教程 - rails开发



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

我有权访问

  • 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中似乎不起作用。

https://src-bin.com


Answer #1

我前几天遇到了同样的问题,发现生成的密钥长度是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





encryption