我想根据参数使用 join 进行非标准查询。

例如,我有 2 个表: a_examples b_examples 都有字段: field_x field_y
当两个表在 field_x (或 field_y )上具有相同的值时,我想连接行。

示例查询可能如下所示:

AExample.joins('INNER JOIN b_examples ON b_examples.field_x = a_examples.field_x')

当我有基于参数的字段名称时会出现问题。
例如,我有变量 field_name 并想用它进行查询。我可以这样做:
AExample.joins("INNER JOIN b_examples ON b_examples.#{field_name} = a_examples.#{field_name}")

此查询有效,但容易受到 sql 注入(inject)的影响。

对于 where 子句,我们有特殊的语法?避免 sql 注入(inject),但没有任何这样的连接。我怎样才能使这个查询安全?

最佳答案

不要尝试这个:
(解释如下)

请改用这个:(包含在另一个答案中)

AExample.joins("INNER JOIN b_examples ON b_examples.#{ActiveRecord::Base.connection.quote_column_name(field_name)} = a_examples.#{ActiveRecord::Base.connection.quote_column_name(field_name)}")
如果未找到该列,它将引发错误,防止恶意代码进入您的查询。
但是我不会在我的应用程序中这样做,因为它看起来很可疑,其他程序员可能不明白发生了什么,它可能实现错误,应该包括可靠的测试,它可能有错误等等。在您的问题中,您只需要构建两个不同的查询,我会用这些信息编写如下内容:
case dynamic_field
when 'field_x'
 AExample.joins('INNER JOIN b_examples ON b_examples.field_x = a_examples.field_x')
when 'field_y'
 AExample.joins('INNER JOIN b_examples ON b_examples.field_y = a_examples.field_y')
else
  raise "Some suspicious parameter was sent!: #{dynamic_field}"
end
或者甚至在您的模型上编写 scopes 并避免此代码四处乱飞。
对于这种性质的问题,就像加密一样,请尝试找到一种解决方法并尽可能避免实现您自己的解决方案。
编辑:sanitize_sql 方法旨在清理 WHERE 子句 ( ActiveRecord::Sanitization ) 的条件:

当您尝试清理 INNER JOINON 子句时,这不是一个选项。
请注意,ActiveRecord::Sanitization 模块只有 WHERE、SET、ORDER 和 LIKE 子句的选项。我找不到列名、INNER JOIN 或 ON 子句的清理方法。也许是一个有用的功能,应该在更高版本的 Rails 上添加。
使用带有字符串的 sanitize_sql 传递它几乎没有过滤,所以如果 field_name 变量有一些恶意代码:
"field_x = a_examples.field_x; DROP TABLE a_examples; --"
它将包含在您的查询中,不会引发任何错误
这种解决方案并不安全,出于类似的原因,我们应该避免编写这种性质的代码。也许你会发现一些对 Arel 或其他 gem 有用的东西,但我强烈建议不要这样做。
编辑 2:
添加了工作解决方案以转义列名。如果输入恶意代码,则会引发错误,因为将找不到具有该名称的列。

关于ruby-on-rails - 基于参数的连接不易受到 sql 注入(inject)的影响,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53521767/

10-13 09:11