非单调SQL ID值

时间:2013-02-21 23:56:16

标签: sql ruby-on-rails security

我被要求随机化所有SQL表的ID值。原因是竞争对手无法根据ID值的增长来推断网站流量。

rails中的默认值是使用ID作为索引,外键和URL路径。这些ID线性增加。

将伪随机整数生成为所有表的ID的最简单方法是什么?有没有我可以抛出的宝石?

注意:Rails有时会出现非整数值的问题,所以我想坚持使用整数。

1 个答案:

答案 0 :(得分:1)

与rails没有多大关系,因为带数据库的约定是使用自动增量主键。

对于新表,为防止rails使用此约定,您需要告诉它不要自动创建id列,而是自己创建它。

# example of creating a users table

create_table :users, id: false do |t|
  t.integer :id
  # other column definitions
end

add_index :users, [:id], unique: true, name: 'index_id_on_users'

然后在您的模型中,您需要在创建记录之前明确设置它。

class User < ActiveRecord::Base
  before_create :set_id

  def set_id
    loop do
      self.id = rand(1<<32)
      break unless User.exists?(self.id)
    end
  end
end

循环只是确保你得到一个唯一的密钥,否则db约束会引发错误。仍然存在竞争条件,但如果您担心碰撞比使用UUID或SHA之类的东西更多。

至于非整数键的问题,我自己从未遇到任何问题,并且使用了UUID和SHA键,以及使用非id列的主键,只需要更多的配置。

对于您当前的型号,您必须从所有ID中删除自动增量,否则我非常确定数据库会忽略您告诉它的任何内容。这显然可以通过在id上发布列更改迁移来完成。

change_column :users, :id, :integer

这里需要注意的是你的db / schema.rb不会反映这个变化,使得db:schema:load没有生成正确的数据库,尽管我可以说我从未使用过rake任务来加载数据库。只需使用db:migrate,一切都应该没问题。

与往常一样,请确保在运行此类命令之前备份数据库。我只是在我的开发环境中在sqlite3上运行它,它似乎运行正常。



更新#1

如果您只关心所有URL,则使用slug而不是ID。有一些宝石将通过一些配置和一些新列来处理这个问题。基本上,我们的想法是将一列用作url param。因此,当您使用URL帮助程序而不是输出/ resources / 1时,它将输出/ resources / some-url-friendly-slug。这可能是像UUID或SHA一样神秘的东西,或者它可以是SEO友好的东西。这取决于模型中是否存在可以被砸的东西。例如,如果它是product_path并且产品有标题,那么slug可能是产品标题的url友好版本,非常适合SEO。