混淆id的一種方法

2021-07-25 09:25:36 字數 2770 閱讀 1666

眾所周知,在web應用的api中,總是會出現資料庫item的id。比如get /posts/1表示獲取id為1的文章內容。這樣做十分簡潔,但存在被人爬資料的風險。比如我可以大致猜測或者試一下id的範圍,1,2,3...10000這樣迭代地爬資料。如果伺服器不做訪問限制,很輕易就能把所有資料就能爬下來。而且,這樣的數字id也會暴露一些資訊,比如id小的一般是更早建立的。

所以要對id進行混淆,混淆有這麼幾個特點:

它是乙個無符號整數到字串的一一對應的函式

雙向的,混淆之後可以恢復,所以不能用hash

不表現出遞增的特徵

不用像加密那樣強,也不用有金鑰

沒有整數範圍的限制。這一條是我加的,google能搜到很多id混淆的方法但它們可能要求id在2^32-1之內,比如對2^32求乙個multiplicative inverse,這是乙個不錯的方法但因為這個限制我沒有採用它。

最簡單的乙個方法是找乙個比較大的數字進行異或,比如1-10跟1093420374進行異或的結果是這樣的:

1 : 1093420375

2 : 1093420372

3 : 1093420373

4 : 1093420370

5 : 1093420371

6 : 1093420368

7 : 1093420369

8 : 1093420382

9 : 1093420383

10: 1093420380

但這比較容易被人猜出是異或,需要再加上別的操作

我看到的乙個比較好的方法也是我目前在用的是:

對id求個hash,取前16位元組,作為segment1

對segment1求hash,取前8位元組,作為segment2

將segment2轉換為整數,加上id,再變回byte array

將segment1和segment2連線起來再求個hash,取前8位元組,作為segment3(用於恢復時的驗證)

連線segment1、2、3,做base64,得到混淆後的id

恢復的時候只用

base64解碼

取前16位元組得到segment1,後8位元組得到segment3,剩餘位元組是segment2

驗證hash(segmemt1+segment2)是否等於segment3

int(segment2)-int(hash(segment1))得到id

這用python實現比較方便,因為python的整數可以無限大,**是這樣的

class

obfuscator:

_head_bytes = 16

_mid_bytes = 8

_tail_bytes = 8

@staticmethod

defbytearray_to_int

(byte_arr):

return int.from_bytes(byte_arr, byteorder='big')

@staticmethod

defint_to_bytearray

(num):

assert isinstance(num, int) and num >= 0

if num == 0:

return

b'0'

result =

while num > 0:

d, m = divmod(num, 256)

num = d

return bytes(result[::-1])

@classmethod

defobfuscate

(cls, uid):

ifnot uid:

return

'' uid_bytes = cls.int_to_bytearray(uid)

seg1 = hashlib.sha1(uid_bytes).digest()[:cls._head_bytes]

seg2 = hashlib.sha1(seg1).digest()[:cls._mid_bytes]

seg2 = cls.int_to_bytearray(uid + cls.bytearray_to_int(seg2))

seg3 = hashlib.sha1(seg1 + seg2).digest()[:cls._tail_bytes]

return base64.urlsafe_b64encode(seg1 + seg2 + seg3).decode()

@classmethod

defrestore

(cls, obscure_str):

ifnot obscure_str:

return -1

seg_bytes = base64.urlsafe_b64decode(obscure_str)

seg1 = seg_bytes[:cls._head_bytes]

seg2 = seg_bytes[cls._head_bytes:-cls._tail_bytes]

seg3 = seg_bytes[-cls._tail_bytes:]

if hashlib.sha1(seg1 + seg2).digest()[:cls._tail_bytes] != seg3:

return -1

seg1 = hashlib.sha1(seg1).digest()[:cls._mid_bytes]

return cls.bytearray_to_int(seg2) - cls.bytearray_to_int(seg1)

反射的另外一種方法

t instance default t type type typeof t system.reflection.constructorinfo constructorinfoarray type.getconstructors system.reflection.bindingflags.ins...

模糊查詢和一種方法

通過這種方法來模糊查詢,可以自定義匹配hql語句 public listsearchuser user user,pageinfo pageinfo else catch exception e 設定query值 private void setvalue query q,user user if ...

解決 side by side 問題的一種方法

vs7.0開始引入了manifest的機制,程式必須經過部署才能執行。release版本的程式可以通過安裝vc 的redistributable包完成部署。debug版本的程式微軟沒有提供對應的redistributable包。如果在沒有安裝vs的機器上執行就會遇到side by side錯誤。對此...