首页 > 代码库 > RailsCast26 Hackers Love Mass Assignment rails中按params创建、更新model时存在的安全隐患

RailsCast26 Hackers Love Mass Assignment rails中按params创建、更新model时存在的安全隐患

Mass assignment是rails中常用的将表单数据存储起来的一种方式。不幸的是,它的简洁性成了黑客攻击的目标。下面将解释为什么及如何解决。



上述表单为一个简单的注册表单。当用户填入name,点击提交时,一个新用户被创建。用户模型被如下定义:

ruby

create_table :users do |t|
  t.string :name
  t.boolean :admin, :default => false, :null => false
end
当用户点击提交时,如下的action被执行:
ruby

def create
  @user = User.new(params[:user])
  if @user.save
    flash[:notice] = "Successfully registered"
    redirect_to :action => ’show’, :id => @user.id
  else
    render :action => :new
  end
end

用户通过传入的params被创建,如前面讨论的,params中的内容不能被充分的信任。下面将展示hacker如何将自己注册为admin的。

攻击网站

如下的curl命令行用于向页面post参数.

terminal
curl -d "user[name]=hacker&user[admin]=1" http://localhost:3000/Users/

上面命令,发送了名字为‘hacker’并为admin的命令。命令行中查看如下:

terminal
Processing UsersController#create (for 127.0.0.1 at 2009-02-03 20:18:54) [POST]
  Session ID: 8daeaad6eb382c903e595e704b626ef7
  Parameters: {"user"=>{"name"=>"hacker", "admin"=>"1"}, "action"=>"create", "controller"=>"users"}
  SQL (0.000390) INSERT INTO users ("name", "admin") VALUES(’hacker’, ’t’)
Redirected to http://localhost:3000/users/show/2

黑客可以如此做,主要是因为mass assignment:我们使用params参数创建一个user,同时黑客传递的参数是符合的。


保护属性

预防这种攻击的方法是限制来自表单的数据被如此存储。Rails有attr_protected方法定义method的属性不能通过mass assignment被设置。

ruby
class User < ActiveRecord::Base
  has_many :comments
  attr_protected :admin
end

在 User model中,将admin属性设置为attr_protected

现在,如果再次发送上述的curl,会看到如下的log信息,即使params hash中提供admin为true,但admin属性没有被保存为true。

terminal

Processing UsersController#create (for 127.0.0.1 at 2009-02-03 20:37:49) [POST]
  Session ID: 381cee077c1367bf0cc410a2259adb96
  Parameters: {"user"=>{"name"=>"hacker", "admin"=>"1"}, "action"=>"create", "controller"=>"users"}
  SQL (0.000327)   INSERT INTO users ("name", "admin") VALUES(’hacker’, ’f’)
Redirected to http://localhost:3000/users/show/5
admin属性被设置成可false。

网站仍然存在漏洞。在应用中,很多模型之间存在关系,如1个user有很多comments,has_many提供了一种通过mass assignment设置comment_ids的方法。现在用如下的命令攻击comment ids.
ruby

curl -d "user[name]=hacker&user[admin]=1&user[comment_ids][]=1&user[comment_ids]=2"
http://localhost:3000/users/create

has_many的关系使得user model具有comment_ids=[],上述命令通过将commend_ids=[1,2]进行了攻击,如下的log展示了hacker用户拥有的comments。

terminal

Processing UsersController#create (for 127.0.0.1 at 2009-02-04 20:27:36) [POST]
Session ID: e6bee21260899c7dce47bc5040dcd467
Parameters: {"user"=>{"name"=>"hacker", "comment_ids"=>["1", "2"], "admin"=>"1"}, "action"=>"create", "controller"=>"users"}
Comment Load (0.001) SELECT * FROM comments WHERE (comments."id" IN (1,2)) 
SQL (0.001) INSERT INTO users ("name", "admin") VALUES(’hacker’, ’f’)
  Comment Update (0.000094)   UPDATE comments SET "title" = ’Comment 1’, "user_id" = 8 WHERE "id" = 1
  Comment Update (0.000071)   UPDATE comments SET "title" = ’Comment 2’, "user_id" = 8 WHERE "id" = 2

为了解决上述问题,最好在model中使用attr_accessible代替attr_protectedattr_accessible罗列出model中可通过mass assignment设置的属性。

更新模的脸定义如下,仅允许name属性可通过mass assignment被设置。

ruby
class User < ActiveRecord::Base
  has_many :comments
  attr_accessible :name
end

最后,log如下:

ruby
Processing UsersController#create (for 127.0.0.1 at 2009-02-04 20:39:15) [POST]
  Session ID: 48b9264e8da94d0a0edadce5e31ac500
  Parameters: {"user"=>{"name"=>"hacker", "comment_ids"=>["1", "2"], "admin"=>"1"}, "action"=>"create", "controller"=>"users"}
  SQL (0.000307)   INSERT INTO users ("name", "admin") VALUES(&rsquo;hacker&rsquo;, &rsquo;f&rsquo;)
Redirected to http://localhost:3000/users/show/9


原文:http://railscasts.com/episodes/26-hackers-love-mass-assignment?view=asciicast

RailsCast26 Hackers Love Mass Assignment rails中按params创建、更新model时存在的安全隐患