如何在Rails 4中对原始SQL进行消毒处理

16
在Rails 3中,我可以使用sanitize_sql_array来清理原始SQL,以应对偶尔需要原始SQL查询的情况。但是在Rails 4中,这似乎已经被删除,或者说不是被删除了,而是移到了ActiveRecord::Sanitization。然而,我现在无法弄清如何调用sanitize_sql_array,那么在Rails 4中清理原始SQL的最佳方法是什么?
我想澄清一下,我说的是完整的原始SQL查询,而不是使用Rail模型。我知道这不是最佳实践,但这是我必须针对此特定查询执行的操作,因为它不能通过Rails的良好ActiveRecord界面表示(相信我,我已经尝试过)。
以下是一个示例调用,这显然比我的实际查询简单:
query = "SELECT * FROM users 
LEFT OUTER JOIN posts ON users.id=posts.user_id
AND posts.topic_id = '#{topic.id}'" 
# ^- Obviously bad and very vulnerable, this is what we're trying to fix
ActiveRecord::Base.connection.select_all(query)
3个回答

19

如果您确实需要编写原始SQL,可以使用quote来进行清理:

conn = ActiveRecord::Base.connection
name = conn.quote("John O'Neil")
title = conn.quote(nil)
query = "INSERT INTO users (name,title) VALUES (#{name}, #{title})"
conn.execute(query)

1
Active Record文档中可以看出,最好的方法是避免将我们自己构建的条件作为纯字符串插入到查询中,而是直接将参数插入到查询中,像这样:
User.find_by("user_name = '#{user_name}' AND password = '#{password}'")

请勿使用字符串条件,而是使用数组或哈希条件。
数组条件:
Client.where("orders_count = ? AND locked = ?", params[:orders], false)

哈希条件:
Client.where(is_active: true)

一个澄清的例子:

class User < ActiveRecord::Base
  # UNSAFE - susceptible to SQL-injection attacks
  def self.authenticate_unsafely(user_name, password)
    where("user_name = '#{user_name}' AND password = '#{password}'").first
  end

  # SAFE
  def self.authenticate_safely(user_name, password)
    where("user_name = ? AND password = ?", user_name, password).first
  end

  # SAFE
  def self.authenticate_safely_simply(user_name, password)
    where(user_name: user_name, password: password).first
  end
end

这里是一些参考资料:


4
嘿 Nick,谢谢你的回复,但我正在寻找适用于原始 SQL 查询的答案,这些查询不经过 ActiveRecord 模型。我已经更新了我的问题,以使其更加清晰明了。 - Colton Voege
@ColtonVoege 抱歉,我误解了问题。就像 @gabrielhilal 所说,“quote”是正确的方法,可以在不使用ActiveRecord模型的情况下清理原始的SQL查询。 - NickGnd
这个答案非常错误,使用'#{user_name}'容易受到SQL注入攻击。 - Hardik
@Hardik,没错。这就是为什么在顶部有一个用大写字母写的注释:# UNSAFE - susceptible to SQL-injection attacks,也许你没有注意到 :) - NickGnd
@Hardik,你能解释一下为什么仅使用引号不安全吗?我现在真的很困扰,每一个答案都互相矛盾(例如,直接下面的答案说引用已经足够了)。这是我试图解决的问题:https://dev59.com/SlgR5IYBdhLWcg3wXcWl - Tallboy
这是一个很好的想法,但是你如何为像CTE这样的东西构建查询? - tibbon

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接