2014-02-19 37 views
22

我已阅读了很多关于这方面的信息,并知道这里有很多相关的问题,但我找不到如何去消毒一切的权威指南。一种选择是消毒的刀片,例如我有以下在我的模型最好的方法去消毒轨道中的用户输入

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)进行清理。我应该在每一个领域的所有观点中进行消毒,以及插入吗?不必做这个手工处处似乎并不十分railsy

感谢所有帮助

回答

54

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

关于呈现潜在不安全用户生成html/JavaScript的内容:作为导轨3,HTML/JavaScript的文本被自动正确转义,以便它显示为在网页上的纯文本,而不是解释为HTML/JavaScript,因此您无需显式消毒(或使用<%= h(potentially_unsafe_user_generated_content)%>

如果我理解正确的话,你不需要担心以这种方式消毒的数据,只要您使用活动记录例如:

比方说,我们的参数图看起来是这样的,因为恶意用户输入下面的字符串到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)) 

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

的好方法(这样做):

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

OR

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“逃逸”为您的字符串内容。你可以它对待像html一样,如果你真的想要,通过做your_string_content.html_safe

但是,只是做一些像<%= your_string_content %>是完全安全的。内容在页面上被视为一个字符串。实际上,如果您使用Chrome开发人员工具或Firebug检查DOM,则实际上应该会看到该字符串的引号。

+0

非常感谢您的快速和彻底的答案 - 非常有帮助!所以我可以基本上允许插入任何东西,只要我使用正确的查询方法,但我仍然需要在视图中的每个用户添加的字段上使用sanitize(field)或simple_format?否则有人不能输入一些JavaScript或HTML,将在我看来这样呈现?似乎有点麻烦,以这种方式手动消毒每个领域 – Dave

+0

也许我对安全卫生与剥离标签之间的混淆,以防止用户格式化他们的内容 – Dave

+0

@Dave噢好吧,作为一个例子,你想确保像''被呈现为纯文本而不是解释为html/javascript?如果是这样,那么你可以安全地将内容插入到页面上。我会为此回答一个快速更新。 –

7

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

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

专门从ActiveRecord::Sanitization::ClassMethods你有sanitize_sql_for_conditions及其两个其他别名sanitize_conditionssanitize_sql。三者确实完全一样。

sanitize_sql_for_conditions

接受一个数组,散列,或SQL条件字符串,并进行消毒 它们放入一个有效的SQL片段为WHERE子句

然而,在ActiveRecord你也有

sanitize_sql_for_assignment

接受一个数组,哈希,或SQL条件字符串,并将其 进行消毒成一个有效的SQL片段的SET子句

  • 注意,这些方法包括在的ActiveRecord :: Base和因此默认情况下,在任何ActiveRecord的模型包括在内。

在另一方面,在ActionController你有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 

参数魔术被称为强参数,docs here

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