2012-06-21 78 views
0

使用Ruby on Rails,我的模型正在使用增加的唯一ID进行创建。例如,第一个用户的用户标识为1,第二个为2,第三个为3.Ruby on Rails安全漏洞,通过id枚举用户枚举

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

有没有好的方法来使用随机ID?

有人为此做了什么?谷歌搜索没有透露任何东西。

+1

我迷路了,为什么这是一个安全漏洞... – John

+0

推断增长率无关安全。 – x1a4

+0

不是一个真正的漏洞,因为它不允许用户以任何方式危害您的应用程序。 Stackoverflow似乎甚至使用增量用户ID。 –

回答

1

我不认为公开用户ID是一种安全漏洞,应该有其他安全机制。也许这是一种“营销安全漏洞”当游客发现你没有那个万个用户,他们答应;-)

总之:

为了避免在URL中的ID都可以使用用户的登录所有地方。确保登录不包含某些特殊字符(./\#?等),这会导致路由问题(使用白名单正则表达式)。此外,登录名称可能稍后不会更改,如果您的网页具有硬链接/搜索引擎条目,则可能会造成麻烦。

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

在您的用户类中,您需要覆盖to_param以使用登录路由而不是用户的ID。这样就不需要替换路线文件中的任何东西,也不需要像link_to @user这样的助手。

class User < ActiveRecord::Base 
    def to_param 
    self.login 
    end 
end 

然后在每个控制器通过User.find_by_login更换User.find

class UsersController < ApplicationController 

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

end 

或者使用before_filter之前更换PARAMS。对于其他控制器,嵌套资源使用params[:user_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 
0

即使您要生成随机的INTEGER ID,它也可能非常容易被破坏。您应该为每个用户(如MD5或SHA1(“asd342gdfg4534dfgdf”))生成一个随机令牌,然后它会对您有所帮助。你应该用这个随机散列链接到用户配置文件。

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

另一种方法是链接到用户与他们的昵称。

但是,我的猜测是知道用户ID或用户数或用户增长率本身不是一个漏洞!

0

添加一个名为random_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)

此外请务必修改您的路线和其他控制器,以利用random_id而不是默认的id

+0

为什么不直接将'id'设置为随机数?这样,你不需要改变一件事情。 – Zabba

0

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

让我们说你,你在Users控制器show动作显示用户信息和代码如下所示:

class UsersController < ActionController::Base 

    before_filter :require_user 

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

end 

此实现易受ID猜测。您可以轻松地通过确保节目的行动解决它总是显示登录的用户的信息:

def show 
    @user = current_user 
end 

现在不管是什么ID给出的网址,你会显示当前的用户配置文件。

让我们说,我们希望允许帐户管理员和帐户所有者访问演出动作:

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

OTH授权逻辑是利用宝石一样CanCan更好的实现。