我的环境
ruby 2.0.0-p195
rails (4.0.0.rc1)
activerecord (4.0.0.rc1)
我想通过id数组对ActiveRecord对象进行排序。 我尝试了按字段排序。
ids = [1,4,2,3]
Foo.where(id: ids).order('FIELD(id, ?)', ids)
然而它失败了。
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?,?,?,?}), ö, ÷, ï, ñ' at line 1:
然后我尝试
ids = [1,4,2,3]
Foo.where(id: ids).order('FIELD(id, #{ids.join(","))')
它当然是成功的。但是我担心它可能有SQL注入风险,因为数组ID是从会话值生成的。
有没有更好更安全的方法?
提前致谢。
答案 0 :(得分:8)
你说得对,这是一个安全漏洞。
我看到两种可能性:
转换为数字
ids = [1,4,2,3].map(&:to_i).compact
Foo.where(id: ids).order("FIELD(id, #{ids.join(',')})")
我认为这应该是安全的,因为您确保值是数字然后删除nil条目。零条目将是非数字条目。
转义字符串
escaped_ids = ActiveRecord::Base::sanitize(ids.join(","))
Foo.where(id: ids).order("FIELD(id, #{escaped_ids})")
你只是逃避字符串的内容......没什么特别的。
答案 1 :(得分:0)
我在 Rails6 上使用 FIELD 方法尝试了这个答案,但遇到了错误。但是,我发现只需将 sql 包装在 Arel.sql()
中即可。
# Make sure it's a known-safe values.
user_ids = [3, 2, 1]
# Before
users = User.where(id: user_ids).order("FIELD(id, 2, 3, 1)")
# With warning.
# After
users = User.where(id: user_ids).order(Arel.sql("FIELD(id, 2, 3, 1)"))
# No warning