使用 Ruby on Rails,我的模型创建的唯一 ID 越来越多。例如,第一个用户的用户 id 为 1,第二个为 2,第三个为 3。
从安全角度来看,这并不好,因为如果有人可以窥探最后创建用户的用户 ID(可能通过创建新用户),他们可以推断出您的增长率。他们还可以轻松猜测用户 ID。
有没有使用随机 ID 的好方法?
人们对此做了什么?谷歌搜索并没有透露太多信息。
使用 Ruby on Rails,我的模型创建的唯一 ID 越来越多。例如,第一个用户的用户 id 为 1,第二个为 2,第三个为 3。
从安全角度来看,这并不好,因为如果有人可以窥探最后创建用户的用户 ID(可能通过创建新用户),他们可以推断出您的增长率。他们还可以轻松猜测用户 ID。
有没有使用随机 ID 的好方法?
人们对此做了什么?谷歌搜索并没有透露太多信息。
我不认为将用户 ID 公开为安全漏洞,应该有其他安全机制。当访问者发现您没有他们承诺的那百万用户时,也许这是一个“营销安全漏洞”;-)
反正:
为了完全避免 url 中的 ID,您可以在所有地方使用用户的登录名。确保登录名不包含一些特殊字符(./\#?
等),这些字符会导致路由出现问题(使用白名单正则表达式)。此外,登录名以后可能不会更改,如果您的页面有硬链接/搜索引擎条目,这可能会导致麻烦。
示例调用是/users/Jeff
and/users/Jeff/edit
而不是/users/522047
and /users/522047/edit
。
在您的用户类中,您需要覆盖to_param
以使用登录名而不是用户的 id。这样就不需要替换路由文件中的任何内容,也不需要替换link_to @user
.
class User < ActiveRecord::Base
def to_param
self.login
end
end
然后在每个控制器中替换User.find
为User.find_by_login
:
class UsersController < ApplicationController
def show
@user = User.find_by_login(params[:id])
end
end
或者使用 abefore_filter
替换之前的参数。对于具有嵌套资源的其他控制器,请使用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
即使您会生成随机 INTEGER id,它也可以很容易地被破坏。您应该为每个用户生成一个随机令牌,例如 MD5 或 SHA1(“asd342gdfg4534dfgdf”),然后它会对您有所帮助。您应该使用此随机哈希链接到用户配置文件。
请注意,这实际上不是哈希概念,它只是一个随机字符串。
例如,另一种方法是用他们的昵称链接到用户。
但是,我的猜测是知道用户 ID 或用户数或用户增长率本身并不是漏洞!
将一个名为random_id
或任何您想要的字段添加到您的用户模型。然后在创建用户时,将此代码放在您的 UsersController 中:
def create
...
user.random_id = User.generate_random_id
user.save
end
并将此代码放在您的 User 类中:
# 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
。
您需要添加适当的授权层以防止未经授权的访问。
假设您show
在控制器的操作中显示用户信息,Users
代码如下所示:
class UsersController < ActionController::Base
before_filter :require_user
def show
@user = User.find(params[:id])
end
end
此实现容易受到 id 猜测的影响。您可以通过确保显示操作始终显示登录用户的信息来轻松修复它:
def show
@user = current_user
end
现在,无论 URL 中给出什么 id,您都将显示当前用户配置文件。
假设我们要允许帐户管理员和帐户所有者访问显示操作:
def show
@user = current_user.has_role?(:admin) ? User.find(params[:id]) : current_user
end
使用像CanCan这样的 gem 可以更好地实现 OTH 授权逻辑。