介紹一款用於搞亂資料庫ID的開源Python庫

老錢發表於2018-04-08

介紹一款用於搞亂資料庫ID的開源Python庫
Hashids是一個非常小巧的跨語言的開源庫,它用來把數字編碼成一個隨機字串。它不同於md5這種演算法這種單向對映,Hashids除了編碼還會解碼。

拿論壇來說,一般帖子在資料庫裡的id都是順序遞增的,但是你可能不想在url上直接把id暴露出來,以免爬蟲直接遍歷id爬取你的內容,給你帶來損失。那現在你就可以使用Hashids把這個id搞亂,讓它失去順序性,無法直接遍歷,這樣就可以直接提高了爬蟲的門檻。著名的Youtube網站就是這麼做的。

我們來看看它怎麼使用 首先安裝一下 pip install hashids

介紹一款用於搞亂資料庫ID的開源Python庫

我們看到hashids不僅可以編碼一個整數,還可以一次編碼多個整數。解碼的時候不需要對字串進行分割,可以直接解碼成多個整數。這在儲存一個帖子的相關帖子時給我們多了一種選擇,一般我們使用json打包多個帖子id放在帖子表的一個欄位裡,現在我們就可以使用hashids把它們編碼成一個字串塞進去了,可以節省一定的儲存空間。不過,除此之外我想不到編碼多個整數有什麼其它的用途了。

hashids需要提供一個salt值,相當於編解碼的私鑰,別人不知道你的私鑰,就無法編碼出對應的帖子的展現key,也無法通過url上的展現key解碼出對應的帖子id。所以想直接遍歷你的帖子服務那就做不到了。

現在我們試試隨便提供字串,對它進行解碼會怎樣

介紹一款用於搞亂資料庫ID的開源Python庫

我們看到這些字串都是非法,所以hashids無法解碼出對應的整數。

下面我們對一段連續整數進行編碼

介紹一款用於搞亂資料庫ID的開源Python庫

可以發現編碼之後的值在直覺上是沒有任何規律可言的。

鑑於hashids是如此的小巧,筆者隨後對它的原始碼進行了一番研究。首先看看它的構造器

介紹一款用於搞亂資料庫ID的開源Python庫

我們發現可以設定編碼後字串的最小長度。如果你不設定這個最小長度,對於一個從0開始的自增id,編碼出來的字串長度一開始只有2位,但是隨著id的增長,編碼後的長度也越來越大,但是最終這個長度值越來越穩定,因為位數越大可以表達的數值就越多。如果我們設定了這個最小長度,在id沒有恐怖的快速增長的情況下,那麼編碼出的長度一開始就是非常穩定的。

然後我們還可以設定對映字典。預設是base64[26+26+10]編碼,如果你不喜歡大小寫敏感,可以改成base36[26+10]編碼,甚至可以改成火星文,如果你真這麼無聊的話。

介紹一款用於搞亂資料庫ID的開源Python庫

注意火星文的字典必須是unicode型別。不然你編碼得到的不是火星文,而是亂碼。具體實現演算法我就跳過了,有點複雜,我就不講了。

介紹一款用於搞亂資料庫ID的開源Python庫

然後它還支援對16進位制字串進行編解碼,看來mongodb的id也可以納入進來了。

最後演算法的實現原理,仔細研究了一下,有點複雜,很難三言兩語講清楚,有興趣的話讀者還是自己閱讀官方文章吧。演算法的作者不保證安全性,不建議將hashids用在安全領域。

維基百科提到一個理想的hash演算法需要滿足下面3個特性

  1. 正向計算hash很容易
  2. 反向破解hash極其困難
  3. hash值碰撞概率極小

hashids滿足第1和第3條,正向計算hash很快,hash值完全沒有碰撞,保證了唯一性。如果知道salt值,還可以逆向通過hash值計算出原值。那第2條是否滿足取決於你的salt祕鑰有多容易被攻擊者拿到。如果你的salt祕鑰來自於常用字典單詞,那攻擊者可以通過彩虹字典快速將祕鑰破解。你把祕鑰好好保護,設定的隨機一點長度長一些,安全性還是可以得到保障的。

最後你可千萬別把祕鑰搞丟了,一旦搞丟了,就意味著所有帖子的展現id需要重新計算一邊,變的跟以前不一樣了,搜尋引擎收錄的所有網頁就失效了,別人外鏈過來的地址全都打不開,這無疑會給你的網站帶來很大的損失。

閱讀相關文章,關注公眾號「碼洞

相關文章