File tree Expand file tree Collapse file tree 3 files changed +35
-1
lines changed
lib/action_dispatch/session Expand file tree Collapse file tree 3 files changed +35
-1
lines changed Original file line number Diff line number Diff line change @@ -38,6 +38,12 @@ been updated in the last 30 days. The 30 days cutoff can be changed using the
38
38
Configuration
39
39
--------------
40
40
41
+ Disable fallback to use insecure session by providing the option `secure_session_only`
42
+ when setting up the session store.
43
+ ```ruby
44
+ Rails.application.config.session_store :active_record_store, :key => '_my_app_session', :secure_session_only => true
45
+ ```
46
+
41
47
The default assumes a `sessions` table with columns:
42
48
43
49
* `id` (numeric primary key),
Original file line number Diff line number Diff line change @@ -60,6 +60,11 @@ class ActiveRecordStore < ActionDispatch::Session::AbstractSecureStore
60
60
SESSION_RECORD_KEY = 'rack.session.record'
61
61
ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS
62
62
63
+ def initialize(app, options = {})
64
+ @secure_session_only = options.delete(:secure_session_only) { false }
65
+ super(app, options)
66
+ end
67
+
63
68
private
64
69
def get_session(request, sid)
65
70
logger.silence do
@@ -136,7 +141,7 @@ def get_session_with_fallback(sid)
136
141
if sid && !self.class.private_session_id?(sid.public_id)
137
142
if (secure_session = session_class.find_by_session_id(sid.private_id))
138
143
secure_session
139
- elsif (insecure_session = session_class.find_by_session_id(sid.public_id))
144
+ elsif !@secure_session_only && (insecure_session = session_class.find_by_session_id(sid.public_id))
140
145
insecure_session.session_id = sid.private_id # this causes the session to be secured
141
146
insecure_session
142
147
end
Original file line number Diff line number Diff line change @@ -299,6 +299,29 @@ def test_session_store_with_all_domains
299
299
end
300
300
end
301
301
302
+ define_method :"test_unsecured_sessions_are_ignored_when_insecure_fallback_is_disabled_#{class_name}" do
303
+ with_store(class_name) do
304
+ with_test_route_set(secure_session_only: true) do
305
+ get '/set_session_value', params: { foo: 'baz' }
306
+ assert_response :success
307
+ public_session_id = cookies['_session_id']
308
+
309
+ session = ActiveRecord::SessionStore::Session.last
310
+ session.data # otherwise we cannot save
311
+ session.session_id = public_session_id
312
+ session.save!
313
+
314
+ get '/get_session_value'
315
+ assert_response :success
316
+
317
+ session.reload
318
+ new_session = ActiveRecord::SessionStore::Session.last
319
+ assert_not_equal public_session_id, new_session.session_id
320
+ assert_not_equal session.session_id, new_session.session_id
321
+ end
322
+ end
323
+ end
324
+
302
325
# to avoid a different kind of timing attack
303
326
define_method :"test_sessions_cannot_be_retrieved_by_their_private_session_id_for_#{class_name}" do
304
327
with_store(class_name) do
You can’t perform that action at this time.
0 commit comments