Skip to content

Commit 8a39f41

Browse files
committed
prevent sql injection attacks by escaping quotes in column names
1 parent b0555bb commit 8a39f41

File tree

4 files changed

+20
-3
lines changed

4 files changed

+20
-3
lines changed

Diff for: activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def quote(value, column = nil)
169169
end
170170

171171
def quote_column_name(name) #:nodoc:
172-
@quoted_column_names[name] ||= "`#{name}`"
172+
@quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
173173
end
174174

175175
def quote_table_name(name) #:nodoc:

Diff for: activerecord/lib/active_record/connection_adapters/mysql_adapter.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def type_cast(value, column)
250250
end
251251

252252
def quote_column_name(name) #:nodoc:
253-
@quoted_column_names[name] ||= "`#{name}`"
253+
@quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
254254
end
255255

256256
def quote_table_name(name) #:nodoc:

Diff for: activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def quote_string(s) #:nodoc:
148148
end
149149

150150
def quote_column_name(name) #:nodoc:
151-
%Q("#{name}")
151+
%Q("#{name.to_s.gsub('"', '""')}")
152152
end
153153

154154
# Quote date/time values for use in SQL input. Includes microseconds

Diff for: activerecord/test/cases/base_test.rb

+17
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ def setup
6767
class BasicsTest < ActiveRecord::TestCase
6868
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
6969

70+
def test_column_names_are_escaped
71+
conn = ActiveRecord::Base.connection
72+
classname = conn.class.name[/[^:]*$/]
73+
badchar = {
74+
'SQLite3Adapter' => '"',
75+
'MysqlAdapter' => '`',
76+
'Mysql2Adapter' => '`',
77+
'PostgreSQLAdapter' => '"',
78+
'OracleAdapter' => '"',
79+
}.fetch(classname) {
80+
raise "need a bad char for #{classname}"
81+
}
82+
83+
quoted = conn.quote_column_name "foo#{badchar}bar"
84+
assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
85+
end
86+
7087
def test_columns_should_obey_set_primary_key
7188
pk = Subscriber.columns.find { |x| x.name == 'nick' }
7289
assert pk.primary, 'nick should be primary key'

0 commit comments

Comments
 (0)