在Rails中转义值(类似于mysql_real_escape_string())

Jas*_*ett 33 ruby-on-rails

我知道准备好的语句,但如果我使用原始SQL,ActiveRecord是否有办法手动转义值?

像这样的东西会很好:

self.escape("O'Malley") # O\'Malley
Run Code Online (Sandbox Code Playgroud)

kon*_*nus 61

你可以做:

Dude.sanitize("O'Malley")
Run Code Online (Sandbox Code Playgroud)

要么

Dude.connection.quote("O'Malley")
Run Code Online (Sandbox Code Playgroud)

两者结果相同: => "'O''Malley'"

  • @NateSymer:是的,那就是,就像,你的意见,男人. (10认同)
  • 我喜欢你的模特名字."老兄",你真棒. (4认同)
  • 在 rails 5.1 中移除了 `sanitize` 函数以支持 `sanitize_sql`。 (4认同)
  • 如果其他人想知道,是的,它们完全相同:[sanitize calls connection.quote](http://apidock.com/rails/ActiveRecord/Base/sanitize/class) (2认同)
  • 从 Rails 5.2.4.1(至少)开始,或者可能在 Rails 5.2.4.1 中,这些似乎没有给出相同的结果,至少使用 Postgres 作为后端时是这样。`Model.connection.quote` 按预期工作(用单引号括起来,双单引号包含任何单引号)。`sanitize_sql` 在所示示例中不执行任何操作(它可能会清理其他内容,但不会转义单引号) (2认同)

jem*_*ger 40

快速浏览ActiveRecord源会显示其方法"sanitize_sql_array",用于清理[string, bind_variable[, bind_variable]]sql语句的类型

你可以直接调用它:

sql = ActiveRecord::Base.send(:sanitize_sql_array, ["insert into foo (bar, baz) values (?, ?), (?, ?)", 'a', 'b', 'c', 'd'])
res = ActiveRecord::Base.connection.execute(sql)
Run Code Online (Sandbox Code Playgroud)

  • 四年后,`sanitize_sql_array`及其表兄弟仍然不是公共API的一部分.是否有方便的公共等价物? (9认同)
  • 杰森:这是一个更好的解决方案,因为它独立于数据库.如果应用程序部署在Heroku上,则当前接受的解决方案(@quest)将不起作用. (2认同)

que*_*est 22

您可以轻松使用mysql2 gem来执行此操作:

irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'mysql2'
=> true
irb(main):004:0> Mysql2::Client.escape("O'Malley") # => "O\\'Malley"
=> "O\\'Malley"
Run Code Online (Sandbox Code Playgroud)

或者如果使用早期的mysql(而不是mysql2)gem:

irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'mysql'
=> true
irb(main):004:0> Mysql.escape_string("O'Malley")
=> "O\\'Malley"
Run Code Online (Sandbox Code Playgroud)

这将允许您转义所需的任何内容,然后插入数据库.您也可以使用sanitize方法在rails应用程序的大多数模型上执行此操作.例如,假设您有一个名为Person的模型.你可以做到.

Person.sanitize("O'Malley")
Run Code Online (Sandbox Code Playgroud)

这应该够了吧.

  • 使用Mysql2 gem:`Mysql2 :: Client.escape("O'Malley")#=>"O \\'Malley"` (10认同)

Nat*_*han 7

如果您不希望在使用@konus发布的解决方案时包含字符串的额外单引号,则可以执行以下操作:

Dude.connection.quote_string("O'Malley")
Run Code Online (Sandbox Code Playgroud)

这将返回"O\'Malley"而不是"'O\'Malley'"

  • 这不会阻止您进行SQL注入。 (2认同)
  • @tvdeyen:您是否愿意以何种方式说明上述内容是否容易受到攻击,特别是与已接受的答案相比较?最终,`quote_string`将取决于所使用的特定ActiveRecord适配器.对于mysql2适配器和抽象mysql适配器,`quote`为字符串值调用`quote_string`并将结果包装在引号中.你在考虑某种多字节注射或其他什么吗?谢谢. (2认同)

And*_*man 5

即使Model.find_by_sql你仍然可以使用问号作为转义值的形式。

只需传递一个数组,其中第一个元素是查询,随后的元素是要替换的值。

Rails API 文档中的示例:

Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
Run Code Online (Sandbox Code Playgroud)