Blob Blame History Raw
commit 4e3120f271a03ee8a1d2b2b4e3ef9b88321b8129
Author: Aaron Patterson <aaron.patterson@gmail.com>
Date:   Tue Aug 2 16:45:40 2011 -0700

    prevent sql injection attacks by escaping quotes in column names

diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 5d066fa..15c6392 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -199,7 +199,7 @@ module ActiveRecord
       end
 
       def quote_column_name(name) #:nodoc:
-        @quoted_column_names[name] ||= "`#{name}`"
+        @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
       end
 
       def quote_table_name(name) #:nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index c0cc7ba..8157c41 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -115,7 +115,7 @@ module ActiveRecord
       end
 
       def quote_column_name(name) #:nodoc:
-        %Q("#{name}")
+        %Q("#{name.to_s.gsub('"', '""')}")
       end
 
       # Quote date/time values for use in SQL input. Includes microseconds
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 8edde52..0894c7d 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -50,6 +50,23 @@ class Boolean < ActiveRecord::Base; end
 class BasicsTest < ActiveRecord::TestCase
   fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
 
+ def test_column_names_are_escaped
+   conn      = ActiveRecord::Base.connection
+   classname = conn.class.name[/[^:]*$/]
+   badchar   = {
+     'SQLite3Adapter'    => '"',
+     'MysqlAdapter'      => '`',
+     'Mysql2Adapter'     => '`',
+     'PostgreSQLAdapter' => '"',
+     'OracleAdapter'     => '"',
+   }.fetch(classname) {
+     raise "need a bad char for #{classname}"
+   }
+
+   quoted = conn.quote_column_name "foo#{badchar}bar"
+   assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
+ end
+
   unless current_adapter?(:PostgreSQLAdapter,:OracleAdapter,:SQLServerAdapter)
     def test_limit_with_comma
       assert_nothing_raised do