Class: Rack::Session::Cookie

Inherits:
Abstract::PersistedSecure show all
Defined in:
lib/rack/session/cookie.rb

Overview

Rack::Session::Cookie provides simple cookie based session management. By default, the session is a Ruby Hash that is serialized and encoded as a cookie set to :key (default: rack.session).

This middleware accepts a :secrets option which enables encryption of session cookies. This option should be one or more random “secret keys” that are each at least 64 bytes in length. Multiple secret keys can be supplied in an Array, which is useful when rotating secrets.

Several options are also accepted that are passed to Rack::Session::Encryptor. These options include:

  • :serialize_json

    Use JSON for message serialization instead of Marshal. This can be
    viewed as a security enhancement.
    
  • :gzip_over

    For message data over this many bytes, compress it with the deflate
    algorithm.
    

Refer to Rack::Session::Encryptor for more details on these options.

Prior to version TODO, the session hash was stored as base64 encoded marshalled data. When a :secret option was supplied, the integrity of the encoded data was protected with HMAC-SHA1. This functionality is still supported using a set of a legacy options.

Lastly, a :coder option is also accepted. When used, both encryption and the legacy HMAC will be skipped. This option could create security issues in your application!

Example:

use Rack::Session::Cookie, {
  key: 'rack.session',
  domain: 'foo.com',
  path: '/',
  expire_after: 2592000,
  secrets: 'a randomly generated, raw binary string 64 bytes in size',
}

Example using legacy HMAC options:

Rack::Session:Cookie.new(application, {
  # The secret used for legacy HMAC cookies, this enables the functionality
  legacy_hmac_secret: 'legacy secret',
  # legacy_hmac_coder will default to Rack::Session::Cookie::Base64::Marshal
  legacy_hmac_coder: Rack::Session::Cookie::Identity.new,
  # legacy_hmac will default to OpenSSL::Digest::SHA1
  legacy_hmac: OpenSSL::Digest::SHA256
})

Example of a cookie with no encoding:

Rack::Session::Cookie.new(application, {
  :coder => Rack::Session::Cookie::Identity.new
})

Example of a cookie with custom encoding:

Rack::Session::Cookie.new(application, {
  :coder => Class.new {
    def encode(str); str.reverse; end
    def decode(str); str.reverse; end
  }.new
})

Defined Under Namespace

Classes: Base64, Identity, Marshal, SessionId

Constant Summary

Constants inherited from Abstract::Persisted

Abstract::Persisted::DEFAULT_OPTIONS

Instance Attribute Summary collapse

Attributes inherited from Abstract::Persisted

#default_options, #key, #same_site, #sid_secure

Instance Method Summary collapse

Methods inherited from Abstract::PersistedSecure

#generate_sid

Methods inherited from Abstract::Persisted

#call, #commit_session, #context

Constructor Details

#initialize(app, options = {}) ⇒ Cookie

Returns a new instance of Cookie.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/rack/session/cookie.rb', line 159

def initialize(app, options = {})
  # support both :secrets and :secret for backwards compatibility
  secrets = [*(options[:secrets] || options[:secret])]

  encryptor_opts = {
    purpose: options[:key], serialize_json: options[:serialize_json]
  }

  # For each secret, create an Encryptor. We have iterate this Array at
  # decryption time to achieve key rotation.
  @encryptors = secrets.map do |secret|
    Rack::Session::Encryptor.new secret, encryptor_opts
  end

  # If a legacy HMAC secret is present, initialize those features.
  # Fallback to :secret for backwards compatibility.
  if options.has_key?(:legacy_hmac_secret) || options.has_key?(:secret)
    @legacy_hmac = options.fetch(:legacy_hmac, 'SHA1')

    @legacy_hmac_secret = options[:legacy_hmac_secret] || options[:secret]
    @legacy_hmac_coder  = options.fetch(:legacy_hmac_coder, Base64::Marshal.new)
  else
    @legacy_hmac = false
  end

  warn <<-MSG unless secure?(options)
  SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
  This poses a security threat. It is strongly recommended that you
  provide a secret to prevent exploits that may be possible from crafted
  cookies. This will not be supported in future versions of Rack, and
  future versions will even invalidate your existing user cookies.

  Called from: #{caller[0]}.
  MSG

  # Potential danger ahead! Marshal without verification and/or
  # encryption could present a major security issue.
  @coder = options[:coder] ||= Base64::Marshal.new

  super(app, options.merge!(cookie_only: true))
end

Instance Attribute Details

#coderObject (readonly)

Returns the value of attribute coder.



157
158
159
# File 'lib/rack/session/cookie.rb', line 157

def coder
  @coder
end

#encryptorsObject (readonly)

Returns the value of attribute encryptors.



157
158
159
# File 'lib/rack/session/cookie.rb', line 157

def encryptors
  @encryptors
end