5

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?

4

2 回答 2

1

据我所知,%s只需将发生的任何事情都插入到您的查询@dangerous.to_s中,您对此负责。

例如,如果@dangerous 是一个整数数组,那么你会得到一个 SQL 错误:

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

将导致以下错误语法:

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

然而:

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

产生正确的查询:

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

因此,在我看来,除非您非常非常清楚自己在做什么,否则您应该让?运营商完成其工作,特别是如果您不相信@dangerous安全的内容。

于 2013-10-25T14:59:18.840 回答
1

%s用于字符串。主要区别在于%s不添加引号。来自ActiveRecord::QueryMethods.where

最后,您可以在模板中使用 sprintf 风格的 % 转义。这与以前的方法略有不同;您有责任确保正确引用模板中的值。这些值被传递给连接器以进行引用,但调用者负责确保它们在生成的 SQL 中包含在引号中。引用后,使用与 Ruby 核心方法相同的转义插入值Kernel::sprintf

例子:

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';

更新:

您正在传递一个数组。%s似乎调用.to_s了参数,因此这可能无法按预期工作:

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'))

对于简单的查询,您可以使用哈希表示法:

User.where(name: ["foo", "bar"])
# SELECT * FROM users WHERE name IN ('foo', 'bar')
于 2013-10-25T14:34:32.717 回答