2

我怎样才能做到这一点,而不冒 SQL 注入攻击的风险?

nearest = Site.minimum('abs(latitude - ' + params[:lat] + ') - abs(longitude - ' + params[:lon] + ')', group: :id)

我试过了:

nearest = Site.minimum(['abs(latitude - ?) - abs(longitude - ?)', params[:lat], params[:lon]], group: :id)

但这似乎不起作用。文档不是很清楚如何实现这一点。

提前致谢!

4

2 回答 2

2

Railssanitize_sql_for_conditions在内部使用来处理占位符。当然,该方法受到保护,因此您不能(干净地)在 ActiveRecord 模型之外使用它。您可以使用以下方法绕过保护send

nearest = Site.minimum(
  Site.send(:sanitize_sql_for_conditions, [
    'abs(latitude - ?) - abs(longitude - ?)',
    params[:lat].to_f, params[:lon].to_f
  ]
)

或者您可以将该逻辑放在一个Site类方法中,这样您就可以在sanitize_sql_for_conditions没有欺骗的情况下使用:

class Site < ActiveRecord::Base
  def self.whatever_this_is(lat, lon)
    minimum(
      sanitize_sql([
        'abs(latitude - ?) - abs(longitude - ?)',
        lat, lon
      ])
    )
  end
end

然后在你的控制器中:

nearest = Site.whatever_this_is(params[:lat].to_f, params[:lon].to_f)

记下to_f电话。如果你不包括那些,那么params[:lat]params[:lon]是字符串,sanitize_sql_for_conditions并将引用它们:

abs(latitude - '11.23') - abs(longitude - '42.6')

您的数据库可能会也可能不高兴看到您尝试从数字中减去字符串,因此最好准确说出您的意思并自己进行类型转换。

于 2012-06-01T19:33:51.983 回答
0

当然,我无法从上面的示例中看出您要完成什么,但看起来您可能不正确地使用了将方法名称作为其第一个参数的最小方法。例如:

Site.minimum(:latitude)

如果你想给它添加条件,我想你会想使用:

Site.where(country: 'USA').group(:id).minimum(:latitude)

同样,此示例不会返回您期望的结果,但它应该更好地解释 API 的使用方式。

于 2012-06-01T13:35:45.847 回答