Rails安全性:完全避免大规模赋值攻击

3

在我的生产代码中,我倾向于不需要mass-assignment功能。(在我的测试代码中,我经常使用它,但在这些情况下,我确实希望设置任意列。)

因此,如果在我的生产代码中,我只需避免使用以下表单:

Article.new(params[:article])  # or create
article.attributes = params[:article]
article.update_attributes(params[:article])

而不是总是手动枚举所有属性,像这样:

Article.new(:title => params[:article][:title], :body => params[:article][:body], ...)

即使我没有使用attr_accessible/attr_protected,我是否免于大规模分配安全问题的影响?

编辑:我不仅仅是禁用大规模分配,我还想能够编写 Article.create!(:blog_id => @blog.id, ...),其中blog_id是一个“不安全”的属性。

3个回答

10

是的,使用第二种方法可以避免用户分配给其他属性。

虽然这是一种更DRY的写法:

Article.new(params[:article].slice(:title, :body))

-或-

def article_params
  params[:article].slice(:title, :body)
end

Article.new(article_params)  # or create
article.attributes = article_params
article.update_attributes(article_params)

2

config/environments/production.rb 文件的末尾添加以下内容:

ActiveRecord::Base.send(:attr_accessible, nil)

但我不想这样做,因为我希望能够在我的测试代码中编写User.create!(:name => 'J. R. Hacker', :admin => true)。我的问题是,如果我没有全局禁用批量赋值,我还安全吗? - Jo Liss
2
以上内容仅适用于您的生产代码,而非测试代码。 - Zabba
啊,对了,当然。但问题在于:如果我这样做,我必须写 a = Article.new; a.blog_id = blog.id; ...; a.save!。我更愿意写 Article.create!(blog_id => blog.id, ...) -- 但是只有在不安全的属性(如blog_id)上开放大规模分配,我才能这样做。所以我想知道这是否完全安全(只要我避免传递受污染的哈希)。 - Jo Liss
你是对的,在这种情况下,你需要为每个属性分配值。你可以使用attr_protected,所有属性都可以被批量赋值,除了那些被标记为受保护的属性。 - Zabba

0

我无法让John Douthat的多参数方法正常工作,因此我想出了以下替代方案(取自我的CommentsController):

def set_params
  @comment.parent_id = params[:blog_comment][:parent_id] 
  @comment.ip_address = request.remote_ip
  @comment.commentator = current_user.username || "anonymous"
  @comment.name = params[:blog_comment][:name]
  @comment.email = params[:blog_comment][:email]
  @comment.url = params[:blog_comment][:url]
end

def create
  @comment = @post.comments.build(params[:blog_comment])
  set_params

  if @comment.save
  ...
end

def update
  @comment = Blog::Comment.find(params[:id])
  set_params

  if @comment.update_attributes(params[:blog_comment])
  ...
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接