Edited at

MySQLで秘密のトークンを0と比較したら危険だけど AR (>= 3.2.12) 経由なら安全

More than 5 years have passed since last update.

User.create!(:token => "c4a307708d83f6af91daee857a089587")

User.where(:token => 0) # => [#<User id: 1, token: "c4a307708d83f6af91daee857a089587">]

秘密のtokenに 0 で比較するとレコードが出てくる。

MySQLだと 'a' = 0 は 'a'.to_f == 0 相当をやってるっぽい。

$ mysql -e "select 'a' = 0"

+---------+
| 'a' = 0 |
+---------+
| 1 |
+---------+

sqlite3 は、安心。

$ sqlite3 /dev/null "select 'a' = 0"

0

2013-02-12 追記

ActiveRecord (>= 3.2.12) から文字列型のカラムには文字列にキャストして比較するようになってました。

ActiveRecord::VERSION::STRING # => "3.2.11"

User.create!(:token => "xxx")
User.where(:token => 0) # => [#<User id: 1, token: "xxx">]
# >> SQL (0.7ms) INSERT INTO `users` (`token`) VALUES ('xxx')
# >> User Load (0.7ms) SELECT `users`.* FROM `users` WHERE `users`.`token` = 0

ActiveRecord::VERSION::STRING # => "3.2.12"

User.create!(:token => "xxx")
User.where(:token => 0) # => []
# >> SQL (0.7ms) INSERT INTO `users` (`token`) VALUES ('xxx')
# >> User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`token` = '0'