如何在rails中混淆记录的ID?

我试图弄清楚如何在rails中混淆我的记录的ID。

例如:典型的路径可能看起来像http:// domain / records / 1 ,因此人们很容易推断出网站在创建新记录时会获得多少流量。

我使用的一个解决方案是使用salt来散列id,但由于我不确定该函数是否是双射的,我最终将其存储在数据库的另一列中并仔细检查唯一性。

我想到的另一个选择是生成随机哈希并将其存储为另一列。 如果它不是唯一的……只需生成另一个。

这样做的最佳方法是什么?

您可以使用内置的OpenSSL库来加密和解密您的标识符,这样您只需要在模型上覆盖to_param 。 您还需要使用Base64将加密数据转换为纯文本。 我会把它粘在一个模块中,以便可以重复使用:

 require 'openssl' require 'base64' module Obfuscate def self.included(base) base.extend self end def cipher OpenSSL::Cipher::Cipher.new('aes-256-cbc') end def cipher_key 'blah!' end def decrypt(value) c = cipher.decrypt c.key = Digest::SHA256.digest(cipher_key) c.update(Base64.decode64(value.to_s)) + c.final end def encrypt(value) c = cipher.encrypt c.key = Digest::SHA256.digest(cipher_key) Base64.encode64(c.update(value.to_s) + c.final) end end 

所以现在你的模型需要看起来像这样:

 class MyModel < ActiveRecord::Base include Obfuscate def to_param encrypt id end end 

然后在您的控制器中,当您需要通过加密ID查找记录时,您将使用以下内容:

 MyModel.find MyModel.decrypt(params[:id]) 

如果您希望加密/解密ID 而不将其存储在数据库中,这可能是最简单的方法。

而不是数字ID,使用某种友好的url或人类可读的slug。 这个部门有很多工具可供选择。 它们不仅对您的用户更友好,而且精心挑选的slu can可以为搜索引擎带来更好的优势。

使用随机字符串生成器或简单调用Digest::SHA1.hexdigest可以很容易地为您的记录生成唯一的随机标识符,从而产生合理的随机和加密唯一结果。

例如,您可以创建一个名为identunique_id的辅助列,用于存储您的公共标识符。 然后你可以覆盖to_param来代替使用它:

 class MyModel < ActiveRecord::Base before_create :assign_ident def self.from_param(ident) find_by_ident(ident) end def to_param self.ident end protected def assign_ident self.ident = Digest::SHA1.hexdigest(SecureRandom.random_number(1<<256).to_s) end end 

从理论上讲,SHA1可能会发生冲突,但由于存储器错误或硬件故障,因此您可能会因软件崩溃而更容易发生故障。 您可以通过生成几十亿个身份来检查它是否符合您的需求,以确定它们是否会发生碰撞,而不应该碰撞。 256位随机数应该为SHA1算法提供足够的数据来进行咀嚼。

阅读@ siannopollo的post后 ,我根据他的post创建了一个Gem(但有一些改进): https : //github.com/pencil/encrypted_id

这是一个gem,它保持数字,不需要数据库迁移,也没有路由更改: https : //github.com/namick/obfuscate_id


我发现这个gem与其他一些gem并不一致,特别是paper_trail。 这是因为它取代了find方法,而paper_trail导致使用实际记录id调用find

所以我一直在使用gem的“scatter_swap”function,但不是其余部分。 这是模型:

 require 'obfuscate_id/scatter_swap' class Page < ActiveRecord::Base # This is a random number that, if changed, will invalidate all existing URLs. Don't change it! @@obfuscate_spin = # random number here, which is essentially the encryption key ## # Generate URL parameter to be used in the URL as the "id" def to_param # Use the obfuscate_id gem's class to "spin" the id into something obfuscated spun_id = ScatterSwap.hash(self.id, @@obfuscate_spin) # Throw any additional attributes in here that are to be included in the URL. "#{spun_id} #{name}".parameterize end def self.find_by_slug!(slug) spun_id = slug[/^[0-9]+/] begin find_by_id! ScatterSwap.reverse_hash(spun_id, @@obfuscate_spin) rescue ActiveRecord::RecordNotFound => e raise ActiveRecord::RecordNotFound, "Couldn't find matching Page." end end end 

在控制器中:

 class PagesController < InheritedResources::Base # Find the page using its URL slug before_filter :find_page, except: [:index, :create, :new] def find_page @page = Page.find_by_slug! params[:id] # If the URL doesn't match exactly, and this is a GET. # We'll redirect to the new, correct URL, but if this is a non-GET, let's let them finish their request instead. if params[:id] != @page.to_param && request.get? redirect_to url_for({ id: @page.to_param }), status: 301 end end end 

作为在那里发生的重定向的替代方法,您可以在页面中简单地包含规范URL。 重定向存在忽略URL中任何查询参数的错误。 这对我的项目来说不是问题,因为我没有。 但规范的URL会更好。