在rails中清理用户输入的最佳方法

Dav*_*ave 27 sanitization ruby-on-rails-4

我已经阅读了很多关于此的内容,并且知道这里有很多相关的问题,但是我找不到关于如何对一切进行消毒的明确指南.一种选择是对插入进行清理,例如我的模型中有以下内容

before_validation :sanitize_content, :on => :create
def sanitize_content
  self.content = ActionController::Base.helpers.sanitize(self.content)
end
Run Code Online (Sandbox Code Playgroud)

我是否需要在每个模型的每个字段上运行它?我猜测:on =>:create也应该删除,以便在更新时运行?

另一种选择是使用simple_format或.html_safe或sanitize(fieldname)在视图中显示数据时进行清理.我应该对每一个领域以及插入的所有观点进行消毒吗?必须在任何地方手动执行此操作似乎并不是很困难

谢谢你的帮助

Pau*_*ter 69

TL; DR
关于用户输入和查询:确保始终使用活动记录查询方法(例如.where),并避免使用字符串插值传递参数; 将它们作为哈希参数值传递,或作为参数化语句传递.

关于渲染可能不安全的用户生成的html/javascript内容:从Rails 3开始,html/javascript文本会自动正确转义,以便在页面上显示为纯文本,而不是解释为html/javascript,因此您不需要明确消毒(或使用<%= h(potentially_unsafe_user_generated_content)%>

如果我理解正确,只要您正确使用活动记录查询方法,就不必担心以这种方式清理数据.例如:

让我们说我们的参数映射看起来像这样,因为恶意用户在user_name字段中输入以下字符串:

:user_name => "(select user_name from users limit 1)"
Run Code Online (Sandbox Code Playgroud)

糟糕的方式(不要这样做):

Users.where("user_name = #{params[:id}") # string interpolation is bad here
Run Code Online (Sandbox Code Playgroud)

生成的查询看起来像:

SELECT `users`.* FROM `users` WHERE (user_name = (select user_name from users limit 1))
Run Code Online (Sandbox Code Playgroud)

以这种方式进行直接字符串插值会将带有键的参数值的文字内容:user_name放入查询中而不进行清理.您可能知道,恶意用户的输入被视为普通的SQL,危险非常明显.

好方法(这样做):

Users.where(id: params[:id]) # hash parameters
Run Code Online (Sandbox Code Playgroud)

要么

Users.where("id = ?", params[:id]) # parameterized statement
Run Code Online (Sandbox Code Playgroud)

生成的查询看起来像:

SELECT `users`.* FROM `users` WHERE user_name = '(select user_name from users limit 1)'
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,Rails实际上为您清理它,只要您将参数作为哈希或方法参数传递(取决于您使用的查询方法).

关于创建新模型记录的数据的清理的情况并不真正适用,因为new或者create方法期望值的散列.即使您尝试将不安全的SQL代码注入到散列中,散列的值也会被视为纯字符串,例如:

User.create(:user_name=>"bobby tables); drop table users;")
Run Code Online (Sandbox Code Playgroud)

结果在查询中:

INSERT INTO `users` (`user_name`) VALUES ('bobby tables); drop table users;')
Run Code Online (Sandbox Code Playgroud)

所以,和上面的情况一样.

我希望有所帮助.如果我错过或误解了任何事情,请告诉我.

编辑 关于转义html和javascript,简短版本是ERB为您"转义"您的字符串内容,以便将其视为纯文本.如果你真的想要的话,你可以把它当作html来对待your_string_content.html_safe.

但是,简单地做一些事情<%= your_string_content %>是非常安全的.内容在页面上被视为字符串.事实上,如果您使用Chrome开发者工具或Firebug检查DOM,您实际上应该看到该字符串周围的引号.


Bry*_*mas 11

因为当我在任何SO答案中找到知识和代码的来源时,我总是很感激,我会为这个问题提供.

ActiveRecord和ActionController都提供了清理sql输入的方法.

具体来说,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)

参数magic称为强参数,这里docs.

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