From be711dddcf48b4e14a1ba41204854add0c9adde2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Guardado=20Castro?= <dev.ivangc@gmail.com>
Date: Fri, 23 Aug 2024 16:57:38 +0200
Subject: [PATCH] Improvoves the trim trask to prevent session fixation.

Removing sessions created before the cutoff period, otherwise, an attacker could extend the session forever: https://guides.rubyonrails.org/security.html#session-fixation-countermeasures
---
 lib/tasks/database.rake          |  5 +++--
 test/tasks/database_rake_test.rb | 10 ++++++++--
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/tasks/database.rake b/lib/tasks/database.rake
index 377a0b6..bfbbfe4 100644
--- a/lib/tasks/database.rake
+++ b/lib/tasks/database.rake
@@ -15,8 +15,9 @@ namespace 'db:sessions' do
   task :trim => [:environment, 'db:load_config'] do
     cutoff_period = (ENV['SESSION_DAYS_TRIM_THRESHOLD'] || 30).to_i.days.ago
     ActiveRecord::SessionStore::Session.
-      where("updated_at < ?", cutoff_period).
-      delete_all
+      where("updated_at < ?", cutoff_period).or(
+        ActiveRecord::SessionStore::Session.where("created_at < ?", cutoff_period)
+      ).delete_all
   end
 
   desc "Upgrade current sessions in the database to the secure version"
diff --git a/test/tasks/database_rake_test.rb b/test/tasks/database_rake_test.rb
index 85fd7be..00f06b5 100644
--- a/test/tasks/database_rake_test.rb
+++ b/test/tasks/database_rake_test.rb
@@ -40,16 +40,22 @@ def test_trim_task
           session.updated_at = 5.minutes.until(cutoff_period)
         end
 
+        Session.create!(data: "fixed session") do |session|
+          session.created_at = 5.minutes.until(cutoff_period)
+        end
+
         recent_session = Session.create!(data: "recent") do |session|
           session.updated_at = 5.minutes.since(cutoff_period)
         end
 
         Rake.application.invoke_task 'db:sessions:trim'
 
-        old_session_count = Session.where("updated_at < ?", cutoff_period).count
+        obsolete_session_count = Session.where("updated_at < ?", cutoff_period).count
+        fixed_session_count = Session.where("created_at < ?", cutoff_period).count
         retained_session = Session.find(recent_session.id)
 
-        assert_equal 0, old_session_count
+        assert_equal 0, obsolete_session_count
+        assert_equal 0, fixed_session_count
         assert_equal retained_session, recent_session
       end