5

我對使用問號的區別感到困惑,例如使用有什麼區別?在ActiveRecord中清理字段時使用%?

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

和使用的sprintf風格字段類型,例如

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

in sanitizing inputs。是否有任何安全優勢,如果你知道你正在尋找一個數字 - 比如ID--而不是字符串,使用%d嗎?或者當字符串出現時你只是要求一個嚴重錯誤的錯誤?

使用Rails 3和4中的newer.where語法,這是否完全改變?

+0

我甚至不知道這是可能的rails2 – phoet

+1

@ muistooshort,它似乎至少在Rails 3中起作用。關於未來打樣的好點,因爲它似乎沒有記錄在任何地方。 –

+0

在3+我會說'在那裏(:巴=> @dangerous)'反正會做正確的事情,如果'@ dangerous'是一個非空數組(但很可惜,[什麼傻事(HTTP:/ /stackoverflow.com/a/12946338/479863)如果它是一個空陣列)。 –

回答

1

%s適用於字符串。主要區別在於%s不會加引號。從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 .

例子:

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

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

更新:

你傳遞一個數組。 %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') 
+0

這不僅僅是引用。%s似乎會將其轉換爲字符串,無論您如何將其轉換爲字符串,結果都將按原樣放入查詢中。不,不。也請看我的答案。 – Giuseppe

+0

@Giuseppe你是對的,我忽略了OP將一個數組傳遞給'%s'。 – Stefan

+0

我猜這裏的主要問題是'%s' **不會**引用,因此對消毒不太有用。然而,它確實逃脫了,所以它也不是無用的。 '@危險'不一定是一個數組。它可以是逗號分隔值的串,例如'@dangerous =「1,2,3」' –

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是安全的內容。

+0

似乎'%s'確實會逃脫,所以它是「安全的」,但是因爲它不會引用,所以可能會有意想不到的結果,包括錯誤。你是對的,可能最好避免它,除非有足夠的理由這麼做。 'Foo.where(「bar =?」,@ dangerous.to_s)'會完成同樣的事情,但不用擔心引用正確。但即使這可能是不必要的,大部分時間甚至可能是不受歡迎的。 –

相關問題