I am trying to hash or encrypt a record's ID for URLs such that people can't view various records simply by guessing different integer IDs.
Essentially, my URLs would be something like this: /plans/0AUTxwoGkOYfiZGd2 instead of /plans/304.
Would the best way to do th开发者_StackOverflow社区is just be to use SHA-1 to hash the plan's id and store it in a hashed_id column for plans? Then, overwrite to_param and add a finder to find by hashed_id?
How do you ensure that the characters generated are 0-9, a-z, or A-Z?
Thanks!
> How do you ensure that the characters generated are 0-9, a-z, or A-Z?
idForURL = URI.escape((Base64.encode64(hash).strip))
I once encrypted the id with Blowfish, it's not super safe but it's kind of convenient and the id gets shorter than for a GUID or a SHA-1.
require 'digest/sha1'
print Digest::SHA1.hexdigest("Let's see how long this gets.")
=> b26316a2db52609f86b540de65282b9d367e085c
i use https://github.com/norman/friendly_id this way:
# app/models/secret.rb; this would go in the model you want to obfuscate
class Secret < ActiveRecord::Base
has_friendly_id :code, :use_slug => true
validates :name, :uniqueness => true
def code
Digest::SHA1.hexdigest self.name
end
end
it’s simple. If your security needs are serious you’d probably want something a little more complex (not to mention more layered than a basic obfuscation technique), but I wanted to share an out-of-the-box way to use a gem that already exists (and may even be in use in your app already)
Include in your model a random code creator, than refer FriendlyId to it.
class Restaurant < ApplicationRecord
extend FriendlyId
friendly_id :random_code, use: :slugged
def random_code
SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
end
I think previous answers help in the encryption part, but no one adresses the first part of the question:
...such that people can't view various records simply by guessing different integer IDs
As Matt Rohrer answered here to be able to access the resource only through the encrypted ID you could use friendly_id this way:
models/plan.rb
class Plan < ApplicationRecord
extend FriendlyId
friendly_id :hashed_id #hashed_id is already a plan column
validates :hashed_id, uniqueness: true
before_create :generate_hash
def generate_hash
# This way you ensure the hash contains letters or numbers but is not very secure
all_letters = [('A'..'Z'), ('a'..'z'), ('0'..'9')].map(&:to_a).flatten
random_string = (0...8).map { all_letters[rand(36)] }.join
self.hashed_id = random_string
end
controllers/plans_controller.rb
class PlansController < ApplicationController
before_action :set_plan, only: [:show, :edit, :update, :destroy]
...
private
def set_plan
# This allows accessibility to plans only through hashed_id
@plan = Plan.find_by!(hashed_id: params[:id])
end
end
If you want a more secure encryption you should use SecureRandom or digest/sha1, maybe these examples can help.
精彩评论