CVE-2019-16782: Observable Discrepancy (CWE-203)
value: There's a possible information leak / session hijack vulnerability in Rack (RubyGem rack). This vulnerability is patched in versions 1.6.12 and 2.0.8. Attackers may be able to find and hijack sessions by using timing attacks targeting the session id. Session ids are usually stored and indexed in a database that uses some kind of scheme for speeding up lookups of that session id. By carefully measuring the amount of time it takes to look up a session, an attacker may be able to find a valid session id and hijack the session. The session id itself may be generated randomly, but the way the session is indexed by the backing store does not use a secure comparison.
CWE description: The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not.
CVSS v3 base score: 5.9
Published: 2019-12-18T20:15Z
Repository: https://github.com/rack/rack
Language: Unknown
Commit date: 2019-12-18 10:07:23 -0800
Commit message: Merge branch 'advisory-fix-1'

* advisory-fix-1:
  Introduce a new base class to avoid breaking when upgrading
  Add a version prefix to the private id to make easier to migrate old values
  Fallback to the public id when reading the session in the pool adapter
  Also drop the session with the public id when destroying sessions
  Fallback to the legacy id when the new id is not found
  Add the private id
  revert conditionals to master
  remove NullSession
  remove || raise and get closer to master
  store hashed id, send public id
  use session id objects
  remove more nils
  try to ensure we always have some kind of object

Diff: diff --cc lib/rack/session/abstract/id.rb
index b15ee3b8,95adbd7b..633f2703
--- a/lib/rack/session/abstract/id.rb
+++ b/lib/rack/session/abstract/id.rb
@@@ -11,34 -12,40 +12,60 @@@ require 'digest/sha2
  
  module Rack
  
    module Session
  
+     class SessionId
+       ID_VERSION = 2
+ 
+       attr_reader :public_id
+ 
+       def initialize(public_id)
+         @public_id = public_id
+       end
+ 
+       def private_id
+         "#{ID_VERSION}::#{hash_sid(public_id)}"
+       end
+ 
+       alias :cookie_value :public_id
+ 
+       def empty?; false; end
+       def to_s; raise; end
+       def inspect; public_id.inspect; end
+ 
+       private
+ 
+       def hash_sid(sid)
+         Digest::SHA256.hexdigest(sid)
+       end
+     end
+ 
      module Abstract
        # SessionHash is responsible to lazily load the session from store.
  
        class SessionHash
 +        using Module.new {
 +          refine Hash do
 +            def transform_keys(&block)
 +              hash = {}
 +              each do |key, value|
 +                hash[block.call(key)] = value
 +              end
 +              hash
 +            end
 +          end
 +        } unless {}.respond_to?(:transform_keys)
 +
 +        def transform_keys(&block)
 +          hash = dup
 +          each do |key, value|
 +            hash[block.call(key)] = value
 +          end
 +          hash
 +        end
 +
          include Enumerable
          attr_writer :id
  
          Unspecified = Object.new
  
diff --cc lib/rack/session/cookie.rb
index 70ddadd6,27c6afc1..d78fa997
--- a/lib/rack/session/cookie.rb
+++ b/lib/rack/session/cookie.rb
@@@ -46,19 -45,19 +46,19 @@@ module Rac
      #       def decode(str); str.reverse; end
      #     }.new
      #   })
      #
  
-     class Cookie < Abstract::Persisted
+     class Cookie < Abstract::PersistedSecure
        # Encode session cookies as Base64
        class Base64
          def encode(str)
 -          [str].pack('m')
 +          ::Base64.encode64(str)
          end
  
          def decode(str)
 -          str.unpack('m').first
 +          ::Base64.decode64(str)
          end
  
          # Encode session cookies as Marshaled Base64 data
          class Marshal < Base64
            def encode(str)