Ruby で適当な連番 ID をちょっと推測しづらいぐらいでスクランブルしたい時のためのコード。Rails なんかは標準で連番 ID なので、ちょっとした ID 隠しをしたい時向けです。あんまりしっかり検証してないので、信用しすぎは禁物。
めちゃくちゃ厳密に隠したい訳ではなく、ロジック知ってないと推測しずらいな程度で、かつ桁数をそこまで気にしたくない、というような用途にしか使えません。ただ、 Salt 値を足したりすることで推測難易度はいくらかあげられるかと思います。
module Scrambler
MINIMUM_SCRAMBLE_DIGIT = 20
SCRAMBLE_BASE = 36
def self.scramble(id)
reversed = id.to_s.rjust(MINIMUM_SCRAMBLE_DIGIT, '0').reverse
"1#{reversed}".to_i.to_s(SCRAMBLE_BASE)
end
def self.unscramble(hash)
reversed = hash.to_i(SCRAMBLE_BASE).to_s.reverse
reversed[0, reversed.length - 1].to_i
end
end
やってることは単純で
- 数値を文字列にして最低桁数(
MINIMUM_SCRAMBLE_DIGIT
)分0埋めする - ひっくり返す
- ひっくり返した先頭に
1
を追加(これをしないと100
なんかが不可逆になる) - その文字列を数値 -> 36進数で変換
というような手順。これを実行すると、
1 => n7q81nvr7zz7k
2 => pbpc1tbqf9slc
3 => rfog1yrpmjlz4
4 => tjnk247ottfcw
5 => vnmo29no138qo
6 => xrls2f3n8d24g
7 => zvkw2kjmfmvi8
8 => 11zk02pzlmwow0
9 => 143j42vfku6i9s
10 => lbcmfxdrxuqrk
みたいな具合になるので、多分そこそこ使い勝手がいいんじゃないかな。割とわからない感じだし。 MINIMUM_SCRAMBLE_DIGIT
を変えることで最小桁数が変わるので、生成後の文字の長さも変わります。
MINIMUM_SCRAMBLE_DIGIT = 10
1 => 51x46bk
2 => 5ighn9c
3 => 5yzv474
4 => 6fj8l4w
5 => 6w2m22o
6 => 7clzj0g
7 => 7t5czy8
8 => 89oqgw0
9 => 8q83xts
10 => 4n1a1vk
変わるけど、復号化のロジックはそのまま使いまわせるので、そんなに困らない。また、ひっくり返した後に付与する 1
は 0
でなければなんでもいいので、それこそ擬似乱数でも構わないです。そうなると scramble 書ける度に違う ID に見えるような発行の仕方になるので、それはそれで使いみちがありそう。
という小ネタでした。おしまい。