Frage

I've been puzzled for a while over the difference between using a question mark, e.g.

Foo.find(:all, :conditions => ['bar IN (?)', @dangerous])

and using sprintf style field types, e.g.

Bar.find(:all, :conditions => ['qux IN (%s)', @dangerous])

in sanitizing inputs. Is there any security advantage whatsoever, if you know you're looking for a number - like an ID - and not a string, in using %d over ?, or are you just asking for a Big Nasty Error when a string comes along instead?

Does this change at all with the newer .where syntax in Rails 3 and 4?

War es hilfreich?

Lösung

%s is intended for strings. The main difference is that %s doesn't add quotes. From ActiveRecord::QueryMethods.where:

Lastly, you can use sprintf-style % escapes in the template. This works slightly differently than the previous methods; you are responsible for ensuring that the values in the template are properly quoted. The values are passed to the connector for quoting, but the caller is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting, the values are inserted using the same escapes as the Ruby core method Kernel::sprintf.

Examples:

User.where(["name = ? and email = ?", "Joe", "joe@example.com"])
# SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';

User.where(["name = '%s' and email = '%s'", "Joe", "joe@example.com"])
# SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';

Update:

You are passing an array. %s seems to calls .to_s on the argument so this might not works as expected:

User.where("name IN (%s)", ["foo", "bar"])
# SELECT * FROM users WHERE (name IN ([\"foo\", \"bar\"]))

User.where("name IN (?)", ["foo", "bar"])
# SELECT * FROM users WHERE (name IN ('foo','bar'))

For simple queries you can use the hash notation:

User.where(name: ["foo", "bar"])
# SELECT * FROM users WHERE name IN ('foo', 'bar')

Andere Tipps

As far as I can tell, %s simply inserts into your query whatever @dangerous.to_s happens to be, and you are responsible for it.

For example, if @dangerous is an array of integers, then you will get an SQL error:

@dangerous = [1,2,3]
User.where("id IN (%s)", @dangerous)

will result in the following incorrect syntax:

SELECT `users`.* FROM `users` WHERE (id IN ([1, 2, 3]))

whereas:

User.where("id IN (?)", @dangerous)

produces the correct query:

SELECT `users`.* FROM `users` WHERE (id IN (1,2,3))

Thus, is seems to me that unless you know very, very well what you are doing, you should let the ? operator do its job, ESPECIALLY if you do not trust the content of @dangerous as safe.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top