Ruby on rails 通过id进行用户枚举的Ruby on Rails安全漏洞

Ruby on rails 通过id进行用户枚举的Ruby on Rails安全漏洞,ruby-on-rails,security,Ruby On Rails,Security,有了RubyonRails,我的模型的唯一ID越来越多。例如,第一个用户的用户id为1、第二个用户id为2、第三个用户id为3 从安全的角度来看,这是不好的,因为如果有人可以窥探最后创建的用户的用户id(可能通过创建新用户),他们可以推断您的增长率。他们还可以轻松猜测用户ID 有没有一个好的方法来代替使用随机ID 人们对此做了什么?谷歌搜索没有透露太多信息。即使生成随机整数id,也可以很容易地进行压缩。您应该为每个用户生成一个随机令牌,如MD5或SHA1(“asd342gdfg4534dfgdf

有了RubyonRails,我的模型的唯一ID越来越多。例如,第一个用户的用户id为1、第二个用户id为2、第三个用户id为3

从安全的角度来看,这是不好的,因为如果有人可以窥探最后创建的用户的用户id(可能通过创建新用户),他们可以推断您的增长率。他们还可以轻松猜测用户ID

有没有一个好的方法来代替使用随机ID


人们对此做了什么?谷歌搜索没有透露太多信息。

即使生成随机整数id,也可以很容易地进行压缩。您应该为每个用户生成一个随机令牌,如MD5或SHA1(“asd342gdfg4534dfgdf”),然后它将帮助您。您应该使用此随机散列链接到用户配置文件

注意,这实际上不是散列概念,它只是一个随机字符串

另一种方法是链接到用户和他们的尼克,例如


然而,我猜知道用户ID、用户数量或用户增长率本身并不是一个漏洞

添加一个名为
random\u id
的字段或任何您想要添加到用户模型的字段。然后,在创建用户时,将以下代码放入UsersController:

def create
  ...
  user.random_id = User.generate_random_id
  user.save
end
并将此代码放置在用户类中:

# random_id will contain capital letters and numbers only
def self.generate_random_id(size = 8)
  alphanumerics = ('0'..'9').to_a + ('A'..'Z').to_a
  key = (0..size).map {alphanumerics[Kernel.rand(36)]}.join

  # if random_id exists in database, regenerate key
  key = generate_random_id(size) if User.find_by_random_id(key)

  # output the key
  return key
end
如果您也需要小写字母,请将它们添加到字母数字中,并确保从内核获得正确的随机数,即
kernel.rand(62)


另外,请确保修改路由和其他控制器,以使用
随机\u id
而不是默认的
id

您需要添加适当的授权层,以防止未经授权的访问

假设您在
Users
控制器的
show
操作中显示用户信息,代码如下所示:

class UsersController < ActionController::Base

  before_filter :require_user

  def show
    @user = User.find(params[:id])
  end

end  
现在,不管URL中给出了什么id,您都将显示当前用户配置文件

假设我们希望允许帐户管理员和帐户所有者访问show操作:

def show
  @user = current_user.has_role?(:admin) ? User.find(params[:id]) : current_user
end

OTE授权逻辑使用类似GEM的更好的实现。

< P>我不认为将用户ID暴露给公众是一个安全缺陷,应该有其他的安全机制。当访问者发现你没有他们承诺的一百万用户时,这可能是一个“营销安全缺陷”;-)

无论如何:

为了避免URL中出现ID,您可以在所有位置使用用户登录。确保登录名不包含导致路由问题的特殊字符(
/\ \?
等)(使用白名单正则表达式)。此外,登录名以后可能不会更改,如果您的页面有硬链接/搜索引擎条目,则可能会导致问题

示例调用是
/users/Jeff
/users/Jeff/edit
而不是
/users/522047
/users/522047/edit

在用户类中,您需要覆盖
to_参数
,以使用路由登录而不是用户id。这样,就不需要替换路由文件或帮助程序中的任何内容,如
链接到@user

class User < ActiveRecord::Base
  def to_param
    self.login
  end
end
或者使用
before_过滤器
替换before的参数。对于具有嵌套资源的其他控制器,请使用
参数[:user\u id]

class UsersController < ApplicationController

  before_filter :get_id_from_login

  def show 
     @user = User.find(params[:id])
  end

  private 
  # As users are not called by +id+ but by +login+ here is a function
  # that converts a params[:id] containing an alphanumeric login to a 
  # params[:id] with a numeric id
  def get_id_from_login
    user = User.find_by_login(params[:id])
    params[:id] = user.id unless user.nil?
  end

end
class UsersController
我不明白为什么这是一个安全漏洞……推断增长率与安全无关。这不是一个真正的漏洞,因为它不允许用户以任何方式危害您的应用程序。Stackoverflow似乎甚至使用增量用户ID。凭据枚举只是登录字符串的一个问题。我们不使用数字ID登录StackOverflow,因此它们不敏感。增长率在财务上是敏感的,可以作为业务发展状况的指标。当然,如果它做得好,你通常希望这些信息是公开的。通过仔细考虑潜在的问题,你可以改进这一点:在模型中保存过滤器之前,将
self.id
设置为随机数。为什么不将
id
本身设置为随机数呢?这样,你就不需要改变任何事情。
class UsersController < ApplicationController

  def show 
     @user = User.find_by_login(params[:id])
  end

end
class UsersController < ApplicationController

  before_filter :get_id_from_login

  def show 
     @user = User.find(params[:id])
  end

  private 
  # As users are not called by +id+ but by +login+ here is a function
  # that converts a params[:id] containing an alphanumeric login to a 
  # params[:id] with a numeric id
  def get_id_from_login
    user = User.find_by_login(params[:id])
    params[:id] = user.id unless user.nil?
  end

end