为啥切片 params 散列会对批量分配造成安全问题?

Posted

技术标签:

【中文标题】为啥切片 params 散列会对批量分配造成安全问题?【英文标题】:Why slicing the params hash poses a security issue on mass-assignment?为什么切片 params 散列会对批量分配造成安全问题? 【发布时间】:2011-11-20 23:00:08 【问题描述】:

通过批量分配防止安全风险的官方方法是使用attr_accessible。然而,一些程序员认为这不是模型的工作(或者至少不是only模型)。在控制器中执行此操作的最简单方法是切片 params 哈希:

@user = User.update_attributes(params[:user].slice(:name))

但是文档指出:

请注意,使用 Hash#except 或 Hash#slice 代替 attr_accessible 清理属性无法提供足够的保护。

这是为什么呢? 为什么params 的白名单切片不能提供足够的保护?

更新:Rails 4.0 will ship strong-parameters,一个精细的参数切片,所以我想整个切片的事情毕竟不是那么糟糕。

【问题讨论】:

对于初学者来说,这只是一个不便。使用attr_accesible,如果需要,您可以在模型中使用:name(尽管没有保存它),但是如果您将.slice 它从params 散列中取出,则不能这样做。使用attr_accesible 也更加语义化,因为它告诉其他人与模型的属性关系,而切片则更加神秘。 @Alex:我知道 attr_accessible 是一种管理批量分配的便捷方式。好的,但是使用 params[:xyz].slice 的安全漏洞是什么? 作为记录,attr_accessible 现在声明“请注意,使用 Hash#except 或 Hash#slice 代替 attr_accessible 来清理属性提供了基本相同的功能,但它有点棘手处理嵌套属性。" 另外,请参阅 Edge API 了解高级 Rails 4 文档,参阅 strong_parameters plugin 了解在 Rails 4 之前使用什么。 【参考方案1】:

来自 DHH 的关于在控制器中切片与单独列入白名单的有趣要点:

https://gist.github.com/1975644

class PostsController < ActionController::Base
  def create
    Post.create(post_params)
  end

  def update
    Post.find(params[:id]).update_attributes!(post_params)
  end

  private
    def post_params
      params[:post].slice(:title, :content)
    end
end

评论强调需要在控制器内进行管理:

https://gist.github.com/1975644#gistcomment-88369

我个人将两者都应用 - attr_accessible 和 slice 以确保没有意外通过。永远不要只依赖黑名单!

【讨论】:

【参考方案2】:

@tokland 你最后的评论在某种程度上是不正确的。除非您的网站将浏览器作为数据进出的唯一入口。

如果您的 web 应用程序具有 API 或与控制器级别的其他 API 保护通信,则会留下漏洞,并且不会对来自其他来源的所有数据进行清理或检查。我建议保持原样,在 application.rb 中打开 ma​​ss-assignment 保护并推进 ActiveSupport FormHelpers 以像 Django/Python 风格一样工作。

【讨论】:

我的哪个cmets?我在这个页面上写了很多 :-) 无论如何,我看不出拥有 API 或浏览器表单之间的区别。当然,重点是避免用户通过篡改属性来更新他不应该更新的属性。 @tokland 您所说的“基本思想是将质量分配保护从模型中移出并移入它所属的控制器中。” 引用自链接文章。但我同意,现在我将其视为模型和控制器 的任务。【参考方案3】:

从 Rails 4 开始,对参数进行切片将是处理批量分配安全性的首选方法。 Rails 核心团队现在已经开发了一个插件来处理这个问题,他们正在努力集成对嵌套属性和签名表单的支持。绝对值得一看:http://weblog.rubyonrails.org/2012/3/21/strong-parameters/

【讨论】:

“基本思想是将质量分配保护从模型中移到它所属的控制器中。”。不错。【参考方案4】:

控制器中的 slice 和 except 问题可能与您的模型中的 accept_nested_attributes_for 一起出现。如果您使用嵌套属性,则需要在控制器中更新它们的所有位置对参数进行切片,这并不总是最简单的任务,尤其是在深度嵌套的场景中。使用attr_accesible 就没有这个问题了。

【讨论】:

啊,嵌套属性,在这种情况下过滤params确实是一件不愉快的工作。【参考方案5】:

只需从参数哈希中删除 :name 即可防止为该操作设置该属性。它仅适用于您记得保护的操作。

但是,这种做法并不能保护您免受使用为关联自动添加的所有方法的滥用。

class User < ActiveRecord::Base
  has_many :comments
end

即使您从参数中删除了comments 属性,也会让您容易受到设置comments_ids 属性的人的攻击。

由于为关联添加了相当多的方法,并且由于它们将来可能会发生变化,因此最佳做法是使用attr_accessible 保护模型上的属性。这将最有效地阻止此类攻击。

【讨论】:

Hash#slice 用于白名单::cmets_ids => [1,2,3], :name => 'hello'.slice(:name) #=> :name= >“你好”。我真的不知道它可能会出现什么问题(危险的短语:-)) 无论如何,正如我所说,我理解为什么 attr_accessible 是处理批量分配安全性的好方法。但我很好奇切片有什么问题,提供了哪些额外的安全性attr_accessible attr_accessible 始终在每个操作中保护您的模型,而无需记住将其放入每个控制器中。 感谢你的回答,你写的都是真的,但我不确定文档说“它不能提供足够的保护”是否意味着“它不安全,因为你可以原谅它” . 从 Rails 4 开始,对参数进行切片将成为处理此问题的首选方法。 weblog.rubyonrails.org/2012/3/21/strong-parameters

以上是关于为啥切片 params 散列会对批量分配造成安全问题?的主要内容,如果未能解决你的问题,请参考以下文章

盐和散列,为啥不使用用户名?

为啥通过切片分配到列表末尾之后不会引发 IndexError? [复制]

为啥我不能将任意迭代分配给步长为 -1 的扩展切片?

为啥 HashMap 需要一个加密安全的散列函数?

为啥可以将切片分配给空接口但不能将其强制转换为相同的空接口

为啥 Rails 6 破坏(散列?)分配给名为“video_key”的表单的 hidden_​​field 的字符串值?