Project.find(:all, :conditions => "name = '#{params[:name]}'")
These examples are vulnerable to SQL injection attacks as an attacker could enter ' OR 1 — and thus, after Rails substituted it into SQL, the query string will be: SELECT * FROM projects WHERE name = '' OR 1 –'
The boolean value 1, and thus name = '' OR 1 is always evaluated to true. The double dash signs start an SQL comment, everything after it will be ignored. Consequently, this query will return all projects in the database and present it to the user. A number sign (#) also starts a comment and /* starts a multi-line comment.
Bypassing Authorization
User.find(:first, "login = '#{params[:name]}' AND password =
'#{params[:password]}'")
params[:name] = ' OR '1'='1
params[:password] = ' OR '2'>'1
params[:name] = ' OR login LIKE '%a%
params[:password] = ' OR ISNULL(1/0) #
Unauthorized Reading
In the example from above, where all projects with a specific name are queried, an attacker can join in the result from a second SELECT statement using the UNION instruction. UNION connects two queries and returns the data in one set, and if the column's data types do not match, they are being converted. The following example introduces SQL column renaming with the AS instruction. It returns a few columns only (contrary to the overall asterisk (*) selector), and renames them according to the column names in the projects table. The actual number of columns can be determined by adding more ones (1) to the SELECT statement. Consequently, the web application believes to return all project names and its descriptions, however, it presents all login names and passwords for the application.
# injecting "') UNION SELECT id,login AS name,password AS
description,1,1,1,1 FROM users /*" will result in:
SELECT * FROM projects WHERE (name = '') UNION SELECT id,login AS
name,password AS description,1,1,1,1 FROM users /*')
Countermeasures
[string containing question marks,
substitution list for the question marks]
As in:
User.find(:first, :conditions => ["login = ? AND password = ?", params[:name],
params[:password]])
Or the same in Rails 1.2:
User.find(:first, :conditions => {:login => params[:name],
:password => params[:password]})