File CVE-2019-16782.patch of Package rubygem-actionpack-4_2.29852
From 80c468c2ad60bed33306589391a8e1f0bebff3fc Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@gmail.com>
Date: Fri, 25 Sep 2015 17:12:46 -0700
Subject: [PATCH 1/3] inherit from our AbstractStore
---
.../lib/action_dispatch/middleware/session/cookie_store.rb | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/lib/action_dispatch/middleware/session/cookie_store.rb b/lib/action_dispatch/middleware/session/cookie_store.rb
index 02b6cfe72779..0e636b82577e 100644
--- a/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -52,11 +52,7 @@ module Session
# JavaScript before upgrading.
#
# Note that changing the secret key will invalidate all existing sessions!
- class CookieStore < Rack::Session::Abstract::ID
- include Compatibility
- include StaleSessionCheck
- include SessionObject
-
+ class CookieStore < AbstractStore
def initialize(app, options={})
super(app, options.merge!(:cookie_only => true))
end
From 2a52a38cb51b65d71cf91fc960777213cf96f962 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= <rafael@franca.dev>
Date: Tue, 17 Dec 2019 18:44:59 -0300
Subject: [PATCH 2/3] Fix possible information leak / session hijacking
vulnerability.
The `ActionDispatch::Session::MemcacheStore` is still vulnerable
given it requires the gem dalli to be updated as well.
CVE-2019-16782
---
actionpack/lib/action_dispatch.rb | 9 +--
.../middleware/session/abstract_store.rb | 14 ++++
.../middleware/session/cache_store.rb | 17 +++--
.../middleware/session/cookie_store.rb | 24 +++++--
.../lib/action_dispatch/request/session.rb | 8 ++-
.../session/abstract_secure_store_test.rb | 67 +++++++++++++++++++
.../dispatch/session/cookie_store_test.rb | 2 +-
11 files changed, 180 insertions(+), 28 deletions(-)
diff --git a/lib/action_dispatch.rb b/lib/action_dispatch.rb
index 0822cdc0a6758..545f01696dd7d 100644
--- a/lib/action_dispatch.rb
+++ b/lib/action_dispatch.rb
@@ -79,10 +79,11 @@ module Http
end
module Session
- autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
- autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
- autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
- autoload :CacheStore, 'action_dispatch/middleware/session/cache_store'
+ autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
+ autoload :AbstractSecureStore, 'action_dispatch/middleware/session/abstract_store'
+ autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
+ autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
+ autoload :CacheStore, 'action_dispatch/middleware/session/cache_store'
end
mattr_accessor :test_app
diff --git a/lib/action_dispatch/middleware/session/abstract_store.rb b/lib/action_dispatch/middleware/session/abstract_store.rb
index 5b0be962235a7..ebe9a4a300ba5 100644
--- a/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -86,5 +86,22 @@ class AbstractStore < Rack::Session::Abstract::ID
request.cookie_jar[key] = cookie
end
end
+
+ class AbstractSecureStore < Rack::Session::Abstract::PersistedSecure
+ include Compatibility
+ include StaleSessionCheck
+ include SessionObject
+
+ def generate_sid
+ Rack::Session::SessionId.new(super)
+ end
+
+ private
+
+ def set_cookie(env, session_id, cookie)
+ request = ActionDispatch::Request.new(env)
+ request.cookie_jar[key] = cookie
+ end
+ end
end
end
diff --git a/lib/action_dispatch/middleware/session/cache_store.rb b/lib/action_dispatch/middleware/session/cache_store.rb
index a6d965a644148..c7b61f96ef8e5 100644
--- a/lib/action_dispatch/middleware/session/cache_store.rb
+++ b/lib/action_dispatch/middleware/session/cache_store.rb
@@ -5,7 +5,7 @@ module Session
# Session store that uses an ActiveSupport::Cache::Store to store the sessions. This store is most useful
# if you don't store critical data in your sessions and you don't need them to live for extended periods
# of time.
- class CacheStore < AbstractStore
+ class CacheStore < AbstractSecureStore
# Create a new store. The cache to use can be passed in the <tt>:cache</tt> option. If it is
# not specified, <tt>Rails.cache</tt> will be used.
def initialize(app, options = {})
@@ -16,7 +16,7 @@ def initialize(app, options = {})
# Get a session from the cache.
def get_session(env, sid)
- unless sid and session = @cache.read(cache_key(sid))
+ unless sid and session = get_session_with_fallback(sid)
sid, session = generate_sid, {}
end
[sid, session]
@@ -24,7 +24,7 @@ def get_session(env, sid)
# Set a session in the cache.
def set_session(env, sid, session, options)
- key = cache_key(sid)
+ key = cache_key(sid.private_id)
if session
@cache.write(key, session, :expires_in => options[:expire_after])
else
@@ -35,14 +35,19 @@ def set_session(env, sid, session, options)
# Remove a session from the cache.
def destroy_session(env, sid, options)
- @cache.delete(cache_key(sid))
+ @cache.delete(cache_key(sid.private_id))
+ @cache.delete(cache_key(sid.public_id))
generate_sid
end
private
# Turn the session id into a cache key.
- def cache_key(sid)
- "_session_id:#{sid}"
+ def cache_key(id)
+ "_session_id:#{id}"
+ end
+
+ def get_session_with_fallback(sid)
+ @cache.read(cache_key(sid.private_id)) || @cache.read(cache_key(sid.public_id))
end
end
end
diff --git a/lib/action_dispatch/middleware/session/cookie_store.rb b/lib/action_dispatch/middleware/session/cookie_store.rb
index b7475d3682cfe..572be8bd9ecb4 100644
--- a/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -52,7 +52,16 @@ module Session
# JavaScript before upgrading.
#
# Note that changing the secret key will invalidate all existing sessions!
- class CookieStore < AbstractStore
+ class CookieStore < AbstractSecureStore
+ class SessionId < DelegateClass(Rack::Session::SessionId)
+ attr_reader :cookie_value
+
+ def initialize(session_id, cookie_value = {})
+ super(session_id)
+ @cookie_value = cookie_value
+ end
+ end
+
def initialize(app, options={})
super(app, options.merge!(:cookie_only => true))
end
@@ -60,7 +69,7 @@ def initialize(app, options = {})
def destroy_session(env, session_id, options)
new_sid = generate_sid unless options[:drop]
# Reset hash and Assign the new session id
- env["action_dispatch.request.unsigned_session_cookie"] = new_sid ? { "session_id" => new_sid } : {}
+ env["action_dispatch.request.unsigned_session_cookie"] = new_sid ? { "session_id" => new_sid.public_id } : {}
new_sid
end
@@ -68,7 +77,7 @@ def load_session(env)
stale_session_check! do
data = unpacked_cookie_data(env)
data = persistent_session_id!(data)
- [data["session_id"], data]
+ [Rack::Session::SessionId.new(data["session_id"]), data]
end
end
@@ -76,7 +85,8 @@ def load_session(env)
def extract_session_id(env)
stale_session_check! do
- unpacked_cookie_data(env)["session_id"]
+ sid = unpacked_cookie_data(env)["session_id"]
+ sid && Rack::Session::SessionId.new(sid)
end
end
@@ -93,13 +103,13 @@ def unpacked_cookie_data(env)
def persistent_session_id!(data, sid=nil)
data ||= {}
- data["session_id"] ||= sid || generate_sid
+ data["session_id"] ||= sid || generate_sid.public_id
data
end
def set_session(env, sid, session_data, options)
- session_data["session_id"] = sid
- session_data
+ session_data["session_id"] = sid.public_id
+ SessionId.new(sid, session_data)
end
def set_cookie(env, session_id, cookie)
diff --git a/lib/action_dispatch/request/session.rb b/lib/action_dispatch/request/session.rb
index 000847e193e20..5c31cffbc1b12 100644
--- a/lib/action_dispatch/request/session.rb
+++ b/lib/action_dispatch/request/session.rb
@@ -87,7 +87,13 @@ def destroy
def [](key)
load_for_read!
- @delegate[key.to_s]
+ key = key.to_s
+
+ if key == "session_id"
+ id&.public_id
+ else
+ @delegate[key]
+ end
end
def has_key?(key)
From 892eab777c418135ce0646e91bc9ebb08a29ab9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= <rafael@franca.dev>
Date: Wed, 18 Dec 2019 17:36:20 -0300
Subject: [PATCH 3/3] Fix syntax error with Ruby 2.2
---
lib/action_dispatch/request/session.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/action_dispatch/request/session.rb b/lib/action_dispatch/request/session.rb
index 5c31cffbc1b12..4bfcf20548a34 100644
--- a/lib/action_dispatch/request/session.rb
+++ b/lib/action_dispatch/request/session.rb
@@ -90,7 +90,7 @@ def [](key)
key = key.to_s
if key == "session_id"
- id&.public_id
+ id && id.public_id
else
@delegate[key]
end