衆所周知,在web應用的API中,老是會出現數據庫item的id。好比GET /posts/1
表示獲取id爲1的文章內容。這樣作十分簡潔,但存在被人爬數據的風險。好比我能夠大體猜想或者試一下id的範圍,1,2,3...10000這樣迭代地爬數據。若是服務器不作訪問限制,很輕易就能把全部數據就能爬下來。並且,這樣的數字id也會暴露一些信息,好比id小的通常是更早建立的。python
因此要對id進行混淆,混淆有這麼幾個特色:web
最簡單的一個方法是找一個比較大的數字進行異或,好比1-10跟1093420374進行異或的結果是這樣的:數據庫
1 : 1093420375 2 : 1093420372 3 : 1093420373 4 : 1093420370 5 : 1093420371 6 : 1093420368 7 : 1093420369 8 : 1093420382 9 : 1093420383 10: 1093420380
但這比較容易被人猜出是異或,須要再加上別的操做服務器
我看到的一個比較好的方法也是我目前在用的是:app
恢復的時候只用函數
這用python實現比較方便,由於python的整數能夠無限大,代碼是這樣的post
pythonclass Obfuscator: _head_bytes = 16 _mid_bytes = 8 _tail_bytes = 8 @staticmethod def bytearray_to_int(byte_arr): return int.from_bytes(byte_arr, byteorder='big') @staticmethod def int_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) result.append(m) num = d return bytes(result[::-1]) @classmethod def obfuscate(cls, uid): if not 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 def restore(cls, obscure_str): if not 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)