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

时间: 2024-12-22 14:52:48

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

Android开发中解析、创建Bitmap对象时OOM的有效解决方法并附上一些干货

先来点鸡汤: Stay hungry,stay foolish 这句话的的解读:我们必须了解自己的渺小.如果我们不学习,科技发展的速度会让我们五年后被清空.所以,我们必须用初学者谦虚的自觉,饥饿者渴望的求知态度,来拥抱未来的知识. 这几天做的项目中需要从图库选择图片或者拍照生成图片,然后展现在IamgeView控件上.当然,从图库选择图片和拍照选择图片的功能实现起来很简单.直接写上代码: CharSequence[] items = { "拍照", "图库" };

Rails中如何避免N+1问题

N+1问题 N+1问题是数据库访问中最常见的一个性能问题,首先介绍一下什么是N+1问题: 举个例子,我们数据库中有两张表,一个是Customers,一个是Orders.Orders中含有一个外键customer_id,指向了Customers的主键id. 想要得到所有Customer以及其分别对应的Order,一种写法是 SELECT * FROM Customers; 对于每一个Customer: SELECT * FROM Orders WHERE Orders.customer_id =

理解ruby on rails中的ActiveRecord::Relation

ActiveRecord::Relation是rails3中添加的.rails2中的finders, named_scope, with_scope 等用法,在rails3统一为一种Relation用法. 以下是返回ActiveRecord::Relation的方法: bind create_with distinct eager_load extending from group having includes joins limit lock none offset order preloa

rails 中加载自定义文件

rails默认生成lib文件夹,但是没有默认加载lib中的文件,可以在config/application.rb中配置如下代码,加载lib文件夹里面定义的module或者是class: config.autoload_paths += %W(#{config.root}/lib) 当然这种方法不只是可以加载lib文件,还可以加载其他自定义的文件夹. 注意的是这些自定义的文件的module或者class名一定要和文件名一直,比如class名为AppStore,那文件名一定要是app_store.r

rails中params[:id]与params["id"]分析

写这个帖子的缘由是因为在页面参数传到rails的controller时用params[:]和params[""]都可以取到值: ? 1 2 3 4 5 6 [1] pry(#<BooksController>)> params => {"action"=>"show", "controller"=>"books", "id"=>"382

【Asp.Net MVC】Avoid Mass Assignment in ASP.NET MVC

Mass Assignment Vulnerability in ASP.NET MVC: http://freshbrewedcode.com/joshbush/2012/03/05/mass-assignment-aspnet-mvc/ 6 Ways To Avoid Mass Assignment in ASP.NET MVC: http://odetocode.com/Blogs/scott/archive/2012/03/11/complete-guide-to-mass-assign

rails中accepts_nested_attributes_for应用

Model: class Blog < ActiveRecord::Base has_many :strip_rules accepts_nested_attributes_for :strip_rules, allow_destroy: true end class StripRule < ActiveRecord::Base belongs_to :blog attr_accessible :rule, :blog_id end 要实现在新建和修改blog时可以添加/删除任意多个strip

rails 中model之间的 association (:inverse_of)

class Customer < ActiveRecord::Base has_many :orders end class Order < ActiveRecord::Base belongs_to :customer end 如上代码两个model在做如下查询的时候: c = Customer.first o = c.orders.first c.first_name == o.customer.first_name # true c.first_name = "other na

rails中一个窗体多个模型——fields_for

借助field_for可以生成表单来处理两个或更多模型对象的数据 先看一个官方的例子,一个表单中有person和permission两个模型,其中每个person包含一个permission <%= form_for(@person) do |person_form| %> First name: <%= person_form.text_field :first_name %> Last name: <%= person_form.text_field :last_name