Ruby on rails 通过id进行用户枚举的Ruby on Rails安全漏洞
有了RubyonRails,我的模型的唯一ID越来越多。例如,第一个用户的用户id为1、第二个用户id为2、第三个用户id为3 从安全的角度来看,这是不好的,因为如果有人可以窥探最后创建的用户的用户id(可能通过创建新用户),他们可以推断您的增长率。他们还可以轻松猜测用户ID 有没有一个好的方法来代替使用随机IDRuby 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
人们对此做了什么?谷歌搜索没有透露太多信息。即使生成随机整数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