开发者

Encrypted ID in URLs

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜