手动生成易于碰撞的混淆散列

时间:2017-11-24 17:16:00

标签: ruby-on-rails ruby-on-rails-5 obfuscation

我正在尝试手动生成一个小哈希来混淆我的webapp ID

(我已经解释了为什么我这样做而不是在这个帖子中使用像SHA,MDA这样的实际哈希,或者甚至像hashid这样的编码哈希:hashids vs pure random hash in id obfuscation

这个哈希是纯随机的:我从字母数字字符串中选择一些数字:

"abcdefghijklmnopqrstuvwxyz1234567890"

这是我的代码:

model.rb

class Model< ApplicationRecord
  before_save :set_hashid
  validates :hashed_id, uniqueness: true

  private

  def set_hashid
    chain = "abcdefghijklmnopqrstuvwxyz1234567890"
    numberdigits = 4

    until @hash.present? && !Model.exists?(hashed_id: @hash)
      @hash = ""
      numberdigits.times do
        @hash << chain[rand(0..chain.size-1)]
      end
    end

    self.hashed_id = @hash
  end

end

效果非常好。创建由chain字符串中的4位数组成的散列。它给出了36 ^ 4 = 1.679.616种可能性

我的模型很丰富(最终应达到1.000.000)

当字段hashed_id中的模型搜索返回false时,哈希值会传递。

虽然有两个问题:

1st:我的数据库是空的,所以它非常快。但是当此列有1百万条记录时,索引列中4位数哈希的搜索时间是多少?有没有办法预测到这一点(试图找到一个我可能会努力的类似的虚拟表)

第2代:我使用uniqueness强制执行验证,因此我想在我的set_hashid内部搜索此哈希值,但在执行冗余验证时也会执行此操作。虽然我热衷于保持验证,以防一个类似的哈希在同一时刻与另一个用户通过测试(非常非常不可能,但谁知道)。有没有办法做不同的事情,所以不进行额外的搜索并保持验证?

1 个答案:

答案 0 :(得分:1)

require 'secure_random'
class Model < ApplicationRecord
  before_validation :set_hashid!, unless: -> { self.hash_id }
  def set_hashid!
    begin
      self.hashed_id = SecureRandom.hex(2)
    end while self.class.exists?(hashed_id: self.hashed_id)
  end
end

begin ... while condtion至少运行一次该块,并在碰撞发生时反复运行self.hashed_id = SecureRandom.hex(2)

2SecureRandom.hex使用的位长(它的长度为4)。

唯一性验证不会提供任何额外的值,因为它只检查具有该值的记录是否存在,并且您已经在回调中检查了该值。应用程序级别验证也很容易出现您试图反击的竞争条件。

相反,这应该由数据库中的唯一索引强制执行。

您还可以创建Postgres函数并使用它生成随机字符串并在触发器中使用它来设置值。但我会从这开始,当性能实际上是一个问题时,请研究一下。