Cyr*_*rus 14 database data-binding obfuscation ruby-on-rails ruby-on-rails-3
我试图弄清楚如何在rails中混淆我的记录的ID.
例如:典型的路径可能看起来像http:// domain/records/1,因此人们很容易推断出网站在创建新记录时会获得多少流量.
我使用的一个解决方案是使用salt来散列id,但由于我不确定该函数是否是双射的,我最终将其存储在数据库的另一列中并仔细检查唯一性.
我想到的另一个选择是生成随机哈希并将其存储为另一列.如果它不是唯一的......只需生成另一个.
这样做的最佳方法是什么?
sia*_*llo 26
您可以使用内置的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
Run Code Online (Sandbox Code Playgroud)
所以现在你的模型需要看起来像这样:
class MyModel < ActiveRecord::Base
include Obfuscate
def to_param
encrypt id
end
end
Run Code Online (Sandbox Code Playgroud)
然后在您的控制器中,当您需要通过加密ID查找记录时,您将使用以下内容:
MyModel.find MyModel.decrypt(params[:id])
Run Code Online (Sandbox Code Playgroud)
如果您希望加密/解密ID 而不将它们存储在数据库中,这可能是最简单的方法.
这是一个保持数值不变的宝石,不需要数据库迁移,也不需要更改路由:https : //github.com/namick/obfuscate_id
我发现该宝石无法与其他宝石配合使用,尤其是paper_trail。这是因为它替换find方法的方式,而paper_trail导致find使用实际记录ID进行调用。
因此,我一直在使用gem的“ scatter_swap”功能,但没有使用其余功能。这是模型:
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
Run Code Online (Sandbox Code Playgroud)
并在控制器中:
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
Run Code Online (Sandbox Code Playgroud)
作为在此处进行重定向的替代方法,您可以在页面中仅包含规范的URL。重定向具有忽略URL中任何查询参数的错误。这对我的项目来说不是问题,因为我没有任何问题。但是规范的URL会更好。