Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
session cookie decrypter for Rails 4.2+
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
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
@erose

This comment has been minimized.

Copy link

erose commented Mar 12, 2017

Lovely, thank you! 🎉

In line 10 of the first one, you use ActiveSupport::MessageEncryptor.key_len which does not exist in Rails 5.0.0. I substituted OpenSSL::Cipher.new('aes-256-cbc').key_len, which was 32 on my machine.

@mbyczkowski

This comment has been minimized.

Copy link
Owner Author

mbyczkowski commented Jan 17, 2018

@tadast

This comment has been minimized.

Copy link

tadast commented Mar 15, 2018

For Rails 5.1 I needed to remove serializer: JSON https://gist.github.com/tadast/769541b7fb82b31466dc620af40fe362

@9mm

This comment has been minimized.

Copy link

9mm commented Jul 1, 2018

How did you guys handle development where Rails.application.secrets.secret_key_base is nil?

@nevans

This comment has been minimized.

Copy link

nevans commented Mar 31, 2020

For what it's worth, this didn't work for me under rails 5.2.4, but here's what worked for me: https://gist.github.com/nevans/558b69f227c243f63552a6f91915424f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.