如何避免 rails 'show' 路由中的序号整数路由(增量 ID)?
How to avoid ordinal, integer routes (incremental ids) in rails 'show' routes?
最简单的 MRE 是 rails g scaffold users
当我们创建用户时,他们的 ID 将是 1、2、3、4 等,他们的 'show' 路由将是 /show/:id
有时我们不希望网站的用户确切知道我们有多少用户 - 有没有简单的方法来混淆这一点?
我可以想出一种手动执行此操作的方法,方法是在注册时添加一个额外的列,其中包含一个随机的 12 位整数,同时还要检查随机生成的整数是否不存在。
但是我想知道有没有更聪明的方法?
备注
示例:https://www.youtube.com/watch?v=Gzj723LkRJY(其中 Gzj723LkRJY
可能是随机生成的,不可预测)
为什么 incremental ids can be a bad idea 的例子(从 2m 52s 到 30 秒)
lots of badly designed sites use incremental counters. It might tell your competitors how many customers you have .. It might let people download all your records easily
..和 another example 为什么增量 ids/routes 可能是坏的:
each post carried a numerical ID that was incremented from the ID of the most recently published one
你可以使用UUID
,它会给你随机的安全令牌,没有人能轻易理解用户的系列。
迁移如下所示
create_table :users, id: :uuid do |t|
t.string :name
t.string :phone
....
t.timestamps
end
希望对你有所帮助。
Rails 实际上并不关心您使用什么作为模型的主要标识符。
As we create users, their id will be 1, 2, 3, 4 etc, and their 'show'
route will be /show/:id
不正确。路线将是 /users/?(:id)
。 运行 rails routes | grep users
查看生成的路由。
您的路由实际上不仅会匹配整数,还会将除有限子集(特别是 .
和 /
之外的任何字符匹配到命名的 :id
段。
因此会将以下内容匹配到用户#show 操作:
GET /users/1
GET /users/gabba-gabba-hey
GET /users/gabba%20gabba%20hey
但不是:
GET /users/1/2
GET /users/gabba/gabba
GET /users/gabba/gabba/hey
Auto-incrementing 整数列默认用作 Rails 中的主键,因为它们简单、简短并且在 99% 的时间内都可以完成工作。通常,如果您切换到 UUID,原因是您正在以需要多个数据库的规模进行操作,并且按顺序生成 ID 不会削减它。将标识符切换为随机生成的东西会使它变得更加难以猜测,但仍然不能替代实际授权访问资源,因为它们仍然可以泄露到日志、电子邮件等中。
I can think of a way to do it manually, by adding an additional column
on sign up with a random 12 digit integer but also checking that the
randomly generated integer doesn't already exist.
But I wonder is there a smarter way?
是的。不要重新发明轮子。
Ruby 已经有内置 SecureRandom#uuid method which generates UUIDs according to RFC 4122:
class User < ApplicationRecord
def generate_uuid
loop do
self.uuid = SecureRandom.uuid
break unless User.exists?(uuid: self.uuid)
end
end
end
由于此处发生冲突的风险极低,因此此循环可能 运行 不会超过一次,并且它只是 运行 在(希望)索引的 EXIST
上查询主键——所以成本比较低。
通过不仅使用整数而且使用字母,您可以生成更短的标识符,从而减少冲突的可能性。
如果您使用的是像 Postgres 这样内置 UUID 支持的数据库,这是一个更好的选择,因为这是真正最好在数据库级别解决的工作,因为它避免了应用程序膨胀并减少了开销。
最简单的 MRE 是 rails g scaffold users
当我们创建用户时,他们的 ID 将是 1、2、3、4 等,他们的 'show' 路由将是 /show/:id
有时我们不希望网站的用户确切知道我们有多少用户 - 有没有简单的方法来混淆这一点?
我可以想出一种手动执行此操作的方法,方法是在注册时添加一个额外的列,其中包含一个随机的 12 位整数,同时还要检查随机生成的整数是否不存在。
但是我想知道有没有更聪明的方法?
备注
示例:https://www.youtube.com/watch?v=Gzj723LkRJY(其中
Gzj723LkRJY
可能是随机生成的,不可预测)为什么 incremental ids can be a bad idea 的例子(从 2m 52s 到 30 秒)
lots of badly designed sites use incremental counters. It might tell your competitors how many customers you have .. It might let people download all your records easily
..和 another example 为什么增量 ids/routes 可能是坏的:
each post carried a numerical ID that was incremented from the ID of the most recently published one
你可以使用UUID
,它会给你随机的安全令牌,没有人能轻易理解用户的系列。
迁移如下所示
create_table :users, id: :uuid do |t|
t.string :name
t.string :phone
....
t.timestamps
end
希望对你有所帮助。
Rails 实际上并不关心您使用什么作为模型的主要标识符。
As we create users, their id will be 1, 2, 3, 4 etc, and their 'show' route will be /show/:id
不正确。路线将是 /users/?(:id)
。 运行 rails routes | grep users
查看生成的路由。
您的路由实际上不仅会匹配整数,还会将除有限子集(特别是 .
和 /
之外的任何字符匹配到命名的 :id
段。
因此会将以下内容匹配到用户#show 操作:
GET /users/1
GET /users/gabba-gabba-hey
GET /users/gabba%20gabba%20hey
但不是:
GET /users/1/2
GET /users/gabba/gabba
GET /users/gabba/gabba/hey
Auto-incrementing 整数列默认用作 Rails 中的主键,因为它们简单、简短并且在 99% 的时间内都可以完成工作。通常,如果您切换到 UUID,原因是您正在以需要多个数据库的规模进行操作,并且按顺序生成 ID 不会削减它。将标识符切换为随机生成的东西会使它变得更加难以猜测,但仍然不能替代实际授权访问资源,因为它们仍然可以泄露到日志、电子邮件等中。
I can think of a way to do it manually, by adding an additional column on sign up with a random 12 digit integer but also checking that the randomly generated integer doesn't already exist. But I wonder is there a smarter way?
是的。不要重新发明轮子。
Ruby 已经有内置 SecureRandom#uuid method which generates UUIDs according to RFC 4122:
class User < ApplicationRecord
def generate_uuid
loop do
self.uuid = SecureRandom.uuid
break unless User.exists?(uuid: self.uuid)
end
end
end
由于此处发生冲突的风险极低,因此此循环可能 运行 不会超过一次,并且它只是 运行 在(希望)索引的 EXIST
上查询主键——所以成本比较低。
通过不仅使用整数而且使用字母,您可以生成更短的标识符,从而减少冲突的可能性。
如果您使用的是像 Postgres 这样内置 UUID 支持的数据库,这是一个更好的选择,因为这是真正最好在数据库级别解决的工作,因为它避免了应用程序膨胀并减少了开销。