如何在Rails中清理sql片段

dim*_*mus 36 sql ruby-on-rails sanitize

我必须清理sql查询的一部分.我可以这样做:

class << ActiveRecord::Base
  public :sanitize_sql
end

str = ActiveRecord::Base.sanitize_sql(["AND column1 = ?", "two's"], '')
Run Code Online (Sandbox Code Playgroud)

但它不安全,因为我公开了受保护的方法.有什么更好的方法呢?

小智 42

你可以使用:

ActiveRecord::Base::sanitize(string)
Run Code Online (Sandbox Code Playgroud)

  • 这委托给'ActiveRecord :: Base.connection.quote`(至少在Rails 4中) (10认同)
  • 此方法已在[PR 26000]上删除(https://github.com/rails/rails/pull/26000) (3认同)
  • 已弃用。新的清理方法 [此处](https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html)。见布莱恩的[答案](/sf/answers/2492583201/) (2认同)

dim*_*mus 15

ActiveRecord::Base.connection.quote Rails 3.x中的技巧


Bry*_*mas 9

这个问题没有说明答案必须来自,ActiveRecord也没有说明它应该是哪个版本的Rails.出于这个原因(并且因为它是顶部和少数之一)关于如何在Rails中清理参数的答案......


这里有一个与Rails 4一起使用的解决方案:

ActiveRecord::Sanitization::ClassMethods你有sanitize_sql_for_conditions和其他两个别名:   sanitize_conditionssanitize_sql.三者确实完全相同.

sanitize_sql_for_conditions

接受SQL条件的数组,散列或字符串,并将它们清理为WHERE子句的有效SQL片段.

您也可以在ActiveRecord中使用

sanitize_sql_for_assignment 哪一个

接受SQL条件的数组,散列或字符串,并将它们清理为SET子句的有效SQL片段.

  • 默认情况下,上述方法包含在ActiveRecord :: Base中,因此包含在任何ActiveRecord模型中.

查看文档


但是,在ActionController中,您可以使用ActionController::Parameters

选择哪些属性应该列入白名单以进行批量更新,从而防止意外暴露不应暴露的属性.为此提供两种方法:requirepermit.

   

params = ActionController::Parameters.new(user: { name: 'Bryan', age: 21 })
req  = params.require(:user) # will throw exception if user not present
opt  = params.permit(:name)  # name parameter is optional, returns nil if not present
user = params.require(:user).permit(:name, :age) # user hash is required while `name` and `age` keys are optional
Run Code Online (Sandbox Code Playgroud)

"参数魔术"称为"强参数"(此处为docs),您可以使用它来在控制器中将参数发送到模型之前对其进行清理.

  • 默认情况下包含上述方法ActionController::Base,因此包含在任何Rails控制器中.

我希望这有助于任何人,如果只是为了学习和揭开Rails的神秘面纱!:)

  • @Matt:吉米是对的,"要求"和"许可"不要自己做任何消毒.但是`ActionController :: Parameters.new`进行了清理,因此所有控制器都应该已经清理所有参数.我有空的时候会更新我的答案,因为我也发现了这个名为rails-html-sanitizer的非常酷的宝石https://github.com/rails/rails-html-sanitizer (4认同)
  • 它实现零消毒,只是验证存在 (2认同)
  • 谢谢布莱恩.我正在向我的控制器发送大量JSON,并处理3s +响应时间.通过消除我的JSON中的冗余,我能够将这些减少到2s,并且通过不实例化ActiveRecord对象进一步将其降低到500ms以下.只是想确定我暴露了安全风险! (2认同)

Luc*_*rna 8

从 rails 5 开始,推荐的方法是使用: ActiveRecord::Base.connection.quote(string)

如此处所述:https : //github.com/rails/rails/issues/28947

ActiveRecord::Base::sanitize(string) 已弃用


pil*_*row 5

您可以protected通过间接调用来绕过方法的本质:

str = ActiveRecord::Base.__send__(:sanitize_sql, ["AND column1 = ?", "two's"], '')
Run Code Online (Sandbox Code Playgroud)

...至少将使您不必将该方法重新设置为public

(我有点怀疑您实际上是否需要执行此操作,但是以上方法可以正常工作。)

  • 并不是使用send来绕开方法受保护性质的忠实粉丝。 (21认同)