黑客當勇於自黑
因為安全漏洞,社區網站被攻破或摧毀的案例已經不在少數。也因此,我們在立項做Discourse.org的時候,就把那些教訓銘記於心。盡管開源的社區軟件已經成千上萬,我們還在為開發一個在骨子裏就非常安全的軟件而努力。
與此同時,我們也重視可移植性——你能隨意將數據從Discourse.org導入或導出。這也是Discourse遵從Creative Commons協議的原因——這一點有別於其他的論壇軟件。作為一名普通用戶,你可以在用戶信息頁面,輕輕松松地將你在Discourse上發表的文字導出並下載下來。
註:Creative Commons(知識共享)是一個相對寬松的版權協議。使用者可以明確知道所有者的權利,不容易侵犯對方的版權,作品可以得到有效傳播。
如果你是站長,你可以在管理面板上輕易地備份或者還原整個網站的數據庫。在瀏覽器裏操作就行。我們一開始就為你設置好了每周的自動備份。為你考慮得這麽周到,算是你有福了!我可是親身經歷了一次慘痛的教訓之後,才在備份方面成為行家裏手的。
這麽多年下來,我們意識到,在安全和數據可移植性之間求得平衡是很難的。能把整個數據庫下載下來,最開心的莫過於黑客了,這意味著他們很快就能在你的系統中獲取據點。那可是終極大獎!
為了緩解這種威脅,我們對Discourse的備份在很多方面逐步加強了限制:
管理員的密碼長度至少需要15個字符;
備份的創建和下載操作都有正式的日誌記錄;
備份的下載令牌是一次性的,會被email到管理員的郵箱,以確認用戶對郵箱地址有完全的控制權。
說到“安全”措施,無非就是深度防禦,因此所有這些加固手段都是有益的……但是,我們仍然需要假設,網上的一些壞家夥能夠通過某種方式獲得你的數據庫的一份拷貝。然後怎麽辦呢?好吧,我們看看數據庫裏有些啥?
l 身份cookie
眾所周知,cookie是瀏覽器用以識別用戶身份的。cookie通常以哈希值的形式存儲,而不會是裸值。因此,暴露哈希值不至於讓你冒充目標用戶。況且,大部分現代的web框架都會快速回收cookie,因此它們的有效期只有短短的10~15分鐘。
l Email地址
盡管用戶對於自己的email被曝光這件事,多少還是有些擔心的。但現如今把email地址當成至寶的人應該也為數不多吧。
l 所有的文章
我們假設這是一個完全公開的網站,沒人會在那裏發布特別敏感的東西。既然所有的文章都是公開的,我們也就不必擔心什麽商業機密或其他秘密資料被揭露了(至少眼下不用擔心)。如果我們確實有一些機密資料要保護,那我以後可以專門寫一篇文章來探討這個問題。
l 密碼的哈希值
剩下的就是密碼的哈希值了。而且,那確實是個嚴重的問題!
現在的問題是,攻擊者拿到了你的數據庫,他們通過大規模的離線攻擊,或者在他們財力能夠承受的範圍內充分利用雲計算資源,攻破了密碼哈希。一旦他們得逞了,他們就能以那個用戶的身份登錄……一直這樣冒充著,直到那個用戶修改密碼。
★ 所以說:如果你知道(甚至只是懷疑)你的數據庫被暴露了,你應該做的第一件事就是重置所有人的密碼。
然而,如果你沒有意識到被拖庫了,怎麽辦呢?你需要先發制人,像世界最流氓大公司的IT部門那樣,每隔30天就重置所有人的密碼嗎?那樣的用戶體驗顯然很糟糕,還會把自身帶入一種嚴重的病態。現實是,當你的數據庫被暴露之後,你可能並不會知道,而等你知道的時候已經太晚了,那時采取任何措施都已枉然。因此,關鍵還在於拖慢攻擊者的節奏,為自己爭取時間去處理和應對。
這樣的話,你可以提供給用戶唯一真正的保護,就只有你存儲的密碼哈希的抗攻擊性了。說到哈希的強度,有兩個因素:
1. 哈希算法。應該盡可能的慢,並且最好跑在GPU上時尤其慢。原因後文細述。
2. 工作因子或叠代次數。盡可能設置高一點,不過也不至於讓你陷入DoS攻擊為限。
我看到過這樣的建議,說你應該把全局的工作因子設得足夠高,以至於在目標平臺上計算一個密碼的哈希值至少需要耗時8毫秒。事實證明,Sam Saffron(和我一樣是Discourse的聯合創始人)早在2013年選擇NIST(美國國家標準與技術研究院)推薦的PBKDF2-HMAC-SHA256和64k叠代,是多麽明智的一個決定啊!我們測試過,這個算法在我們目前的服務器(相當高端的Skylake 4.0 GHz)上,運行我們現有的Ruby登錄代碼,確實需要耗費大概8毫秒。
不過,那是4年前的事了。現如今,我們數據庫裏的密碼哈希還這麽安全嗎?4年以後或者10年以後呢?我們在做的是一個開源軟件,是一個長期項目,我們需要確信我們做出合理的決定,以保護每一個人。俗話說得好,防人之心不可無,是時候戴上達斯頭盔演一回壞人了——讓我們自己來攻擊自己的哈希!
我們先用惡貫滿盈的單GPU(GTX 1080 Ti)小試一下。先給些參考數據:PBKDF2-HMAC-SHA256在1080型號上可以達到1180 kH/s(千次哈希/秒),而在1080 Ti上可以達到1640kH/s。看吧,還是同一代視頻卡呢,在攻擊哈希的效率方面竟然能提升將近40%。細思極恐!
首先,我們來做一個小小的試驗,看看是否行得通。我下載了Hashcat。(註:Hashcat是當前最強大的開源密碼恢復工具,可以訪問Hashcat.net了解更多詳情。)我登錄進我們的演示網站try.discourse.org,然後創建了一個新帳號,並設置了密碼0234567890。接著,我查看了數據庫,發現為那個新用戶生成了如下的哈希值和鹽:
hash
93LlpbKZKficWfV9jjQNOSp39MT0pDPtYx7/gBLl5jw=
salt
ZWVhZWQ4YjZmODU4Mzc0M2E2ZDRlNjBkNjY3YzE2ODA=
Hashcat對輸入文件的格式是有要求的:一行只描述一個哈希,須註明哈希類型,叠代次數,鹽和哈希值,並且各部分之間用冒號隔開,如下:
sha256:64000:ZWVhZWQ4YjZmODU4Mzc0M2E2ZDRlNjBkNjY3YzE2ODA=:93LlpbKZKficWfV9jjQNOSp39MT0pDPtYx7/gBLl5jw=
讓我們把它交給Hashcat,看它是否搞得定!
./h64 -a 3 -m 10900.\one-hash.txt 0234567?d?d?d
註意:這裏故意降低了計算量,只讓它猜3個數字。而不出所料的是,我們很快就把密碼攻破了!看到最後的密碼了嗎?我們得手了!
sha256:64000:ZWVhZWQ4YjZmODU4Mzc0M2E2ZDRlNjBkNjY3YzE2ODA=:93LlpbKZKficWfV9jjQNOSp39MT0pDPtYx7/gBLl5jw=:0234567890
到目前為止,我們知道上面的攻擊方法是可行的。然後讓我們進入正題。不過,我們一開始先簡單一點——蠻力攻擊最簡單的8位數字組成的Discourse密碼需要多久呢——也就108個組合,1個億吧。
Hash.Type........:PBKDF2-HMAC-SHA256
Time.Estimated...:Fri www.yigouylpt2.com Jun 02 00:15:37 2017 (1 hour, 0 mins)
Guess.Mask.......:?d?d?d?d?d?d?d?d [8]
即使用的是一款極品GPU……記住,這裏我們只是測了一個哈希,也就是說,表中的每一行(用戶)都需要耗費你1小時。還有更打擊你的消息:Discourse已經禁用8個字符的密碼有段時間了。如果我們嘗試破解更長的數字型密碼,需要花多少時間呢?
?d?d?d?d?d?d?d?d?d[9]
Fri Jun 02 10:34:422017 (11 hours, 18 mins)
?d?d?d?d?d?d?d?d?d?d[10]
Tue Jun 06 17:25:192017 (4 days, 18 hours)
?d?d?d?d?d?d?d?d?d?d?d[11]
Mon Jul 17 23:26:062017 (46 days, 0 hours)
?d?d?d?d?d?d?d?d?d?d?d?d[12]
Tue Jul 31 23:58:302018 (1 year, 60 days)
要知道,全數字的密碼模式太簡單了,小朋友才會用!要不要試一些真實的密碼,比如只含小寫字母,或者小寫+大寫+數字的組合?
Guess.Mask.......:?l?l?l?l?l?l?l?l [8]
Time.Estimated...:Mon Sep 04 10:06:00 2017 (94 days, 10 hours)
Guess.Mask.......:?1?1?1?1?1?1?1?1 [8] (-1 = ?l?u?d)
Time.Estimated...:Sun Aug 02 09:29:48 2020 (3 years, 61 days)
目前看來,像這樣的蠻力攻擊——拿字母或數字一個一個去試——在高端GPU上的表現也不算驚艷。但如果我們把數字除以8呢……手段是,在一臺機器裏裝上8張顯卡。這是小公司財力所能及的,或者有些有錢的個人也能做到。遺憾的是,38個月除以8得出的結果也並沒有大幅降低攻擊時間。別急,如果以舉國之力來做這件事呢?他們財力雄厚,可以使用幾千個這樣的GPU(1.1天),甚至可能幾萬個GPU(2.7小時),然後呢……好了,即使密碼的最低要求是10個字符,你在那種情況下也麻煩大了!
如果我們想讓Discourse扛得住全國性的攻擊,很顯然,我們還需要努力。Hashcat有一個方便的基準模式,它在一臺裝有8張Nvidia GTX 1080 GPU的設備上測試,然後根據結果按順序列出了最強(最慢)的哈希算法。從那份清單上,我看到了脫穎而出的bcrypt、scrypt和PBKDF2-HMAC-SHA512。
我用Hashcat的測試結果給了我一些信心,說明Discourse存入數據庫的密碼哈希並沒有太偏離正確軌道。但是,我想要的是完全的確信,於是我請了一位有安全和穿透測試背景的人,來嘗試破解當前托管在我們這兒的兩個非常熱門的Discourse站點的密碼哈希(當然簽了保密協議)。結果是這樣的:
有人提供給我兩套來自兩個不同的Discourse社區的密碼哈希,分別包含5909個和6088個哈希值。兩者都使用了PBKDF2-HMAC-SHA256算法,並且工作因子是64k。我的機器配有Nvidia GTX1080 Ti GPU,使用Hashcat計算哈希的速率大約是每秒27000次。
所有Discourse社區都共同遵循的密碼規則如下:
所有用戶必須擁有一個最小長度是10個字符的密碼;
所有管理員的密碼長度至少是15個字符;
用戶不能使用10000個最常用的密碼黑名單上的密碼;
用戶可以選擇創建新的用戶名和密碼,或者使用各種第三方認證機制(Google、Facebook、Twitter等)。如果用戶選擇了這個選項,就會自動生成一個安全的32個字符長度的隨機密碼。給定的任何密碼,是無法區分它是人工輸入的還是自動生成的。
利用上述密碼規則制定出模板,我花了大概3周時間在11997個哈希裏破解出了39個,其中25個是xxx社區的,14個是yyy社區的。
這是一位安全領域的研究員,他經常做如此這般的審計。因此,所有的攻擊都使用了字典,並且根據他以前的經驗總結出來的高效攻擊模式——這不是真正意義上的蠻力攻擊。他恢復出來的密碼如下(其中有一個是重復的):
007007bond
123password
1qaz2wsx3e
A3eilm2s2y
Alexander12
alexander18
belladonna2
Charlie123
Chocolate1
christopher8
Elizabeth1
Enterprise01
Freedom123
greengrass123
hellothere01
I123456789
Iamawesome
khristopher
l1ghthouse
l3tm3innow
Neversaynever
password1235
pittsburgh1
Playstation2
Playstation3
Qwerty1234
Qwertyuiop1
qwertyuiop www.acnet.cn 1234567890
Spartan117
springfield0
Starcraft2
strawberry1
Summertime
Testing123
testing1234
thecakeisalie02
Thirteen13
Welcome12
如果我們把攻擊力度提升到8倍,並且允許的時間翻倍,假設碰到一個打了雞血的攻擊者,或者他有一套很靈光的字典和模板,可以預見,他可能最後破解出 39 x 16 = 624個密碼,也就是相當於所有用戶中的5%。這是合理的估算,但仍然比我想象的要高。在Discourse的未來版本裏,我們肯定會規劃加入哈希類型表。這樣我們就能在將來1~2年裏,切換到一種更為安全(慢得多)的密碼哈希策略。
bcrypt$2*$, Blowfish (www.huazongyule.com/ Unix)
20273 H/s
scrypt
886.5 kH/s
PBKDF2-HMAC-SHA512
542.6 kH/s
PBKDF2-HMAC-SHA256
1646.7 kH/s
通過這次演練,我現在對我們最糟糕的安全場景有了一個更為深入的理解,也就是,數據庫被盜走,然後在線下遭遇專業的密碼哈希攻擊。同時也讓我更加自信地推薦和支持我們的開發工作,使得Discourse的用戶人人都很安全。因此,如果你在安全實施方面並不完全確信(像我一樣),是時候來驗證一下那些假設啦。別等著黑客來攻擊你——作為黑客,要勇於自黑!
黑客當勇於自黑