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

时间:2014-02-19 16:15:59

标签: ruby-on-rails-4 sanitization

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

before_validation :sanitize_content, :on => :create
def sanitize_content
  self.content = ActionController::Base.helpers.sanitize(self.content)
end

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

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

感谢您的帮助

2 个答案:

答案 0 :(得分:68)

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

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

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

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

:user_name => "(select user_name from users limit 1)"

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

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

生成的查询如下所示:

SELECT `users`.* FROM `users` WHERE (user_name = (select user_name from users limit 1))

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

好方法(这样做):

Users.where(id: params[:id]) # hash parameters

Users.where("id = ?", params[:id]) # parameterized statement

生成的查询如下所示:

SELECT `users`.* FROM `users` WHERE user_name = '(select user_name from users limit 1)'

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

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

User.create(:user_name=>"bobby tables); drop table users;")

查询中的结果:

INSERT INTO `users` (`user_name`) VALUES ('bobby tables); drop table users;')

所以,与上述情况相同。

我希望有所帮助。如果我错过或误解了任何内容,请告诉我。

修改 关于转义html和javascript,简短的版本是ERB&#34;逃避&#34;您的字符串内容,以便将其视为纯文本。如果你真的想要,你可以通过your_string_content.html_safe 视为html。

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

答案 1 :(得分:11)

因为我总是欣赏当我在任何SO答案中找到知识和代码的来源时,我将为此问题提供。

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

具体来自ActiveRecord::Sanitization::ClassMethods您有 sanitize_sql_for_conditions 及其他两个别名:   sanitize_conditions sanitize_sql 。这三者确实完全相同。

sanitize_sql_for_conditions

  

接受SQL条件的数组,散列或字符串并进行清理   它们是一个有效的SQL片段,用于WHERE子句

但是,在ActiveRecord中你也有

sanitize_sql_for_assignment

  

接受SQL条件的数组,散列或字符串并对其进行清理   到一个有效的SQL片段用于SET子句

  • 请注意,这些方法包含在ActiveRecord :: Base中,因此默认包含在任何ActiveRecord模型中

另一方面,ActionController docs here允许您ActionController::Parameters

  

选择哪些属性应列入白名单以进行批量更新   从而防止意外暴露不应暴露的东西。   为此提供了两种方法:需要允许

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

参数magic称为强参数,DEMO

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