面試官:為什么在忘記密碼時只能重置密碼,而不能發送舊密碼?
有一天,Joe 發現了一個他常去的論壇書簽,但已經有半年沒訪問了。Joe 想看看這個論壇現在有什么變化,于是他進入論壇,輸入用戶名和密碼,卻收到密碼錯誤的提示。
幾次嘗試后,系統提示 Joe 使用“忘記密碼”功能。于是 Joe 填寫了他的郵箱,查收了收件箱中的重置密碼鏈接。盡管 Joe 最終通過重新設置的密碼成功登錄,但有一個問題讓他百思不得其解:
奇怪,為什么我必須重置密碼?為什么不直接把舊密碼發到我的郵箱呢?
很多人可能都有像 Joe 一樣的疑問。發送舊密碼不是更好嗎?為什么要強迫我更改密碼?
這個看似簡單的問題實際上涉及到許多信息安全相關的概念。讓我們慢慢尋找問題的答案,并順便學習一些信息安全的基礎知識!
數據庫被盜
我們經常會看到新聞報道某個網站的數據再次被盜,所有客戶的個人數據被泄露,比如知名域名托管網站 GoDaddy 之前泄露了 120 萬用戶記錄。
這里我想和大家討論兩個問題:
- 數據這么容易泄露嗎?
- 數據泄露可能會帶來什么后果?
首先來看第一個問題,很多安全漏洞會導致數據泄露,而一些攻擊這些漏洞的方法比你想象的要簡單百倍。
圖片
你想象中的黑客可能像下面這樣,輸入一堆你不知道他們在做什么的命令。屏幕顯示出很多黑底白字或綠字的界面,完全看不懂,但他們一操作,網站就被黑了。
但有些漏洞可能通過在地址欄上改幾個字就能成功攻擊,即使你不懂任何代碼。
舉個例子,假設今天有一個購物網站。買了東西下單后,訂單確認并重定向到訂單頁面,頁面上有很多你的數據,比如姓名、收貨地址、聯系電話、郵箱等。
然后你發現訂單頁面的 URL 是:https://shop.example.com/orders?id=14597。
巧合的是,你的訂單號也是 14597。在好奇心驅使下,你試著把這個數字改成 14596,然后按下回車鍵。
一些攻擊是如此簡單和平凡,只需更改一個數字,你就可以看到別人的數據。如果你知道如何編寫程序,你可以寫一個腳本自動獲取從 ID 1 到 ID 15000 的數據。然后你就擁有了這個購物網站上所有 15000 個訂單的信息——上萬客戶的個人數據。
這種漏洞有一個術語,叫做 IDOR(Insecure Direct Object References),即不安全的直接對象引用。導致這種漏洞的原因是開發時工程師沒有注意權限控制,允許用戶訪問其他人的數據。
有些人可能認為我只是為了在本文中說明問題而簡化了事情,但現實中的攻擊并不像這個例子這么簡單。
這句話只對了一半。大多數網站確實沒有這么明顯的漏洞,攻擊方法也更復雜。然而,令人恐懼的是,有些網站就是這么簡單——改一個數字就能訪問別人的數據。
圖片
例如,這兩個是真實的 IDOR 漏洞:
- xarefit 有訪問/下載所有會員個人數據的權限。
- DoorGods 的 IDOR 導致個人數據泄露。
今后,只要你在 URL 欄看到這種數字,你可以嘗試做一些更改。即使你不會編寫程序,也可能發現 IDOR 漏洞。
個人數據泄露后會怎樣?
我們已經看到了從防御不力的網站泄露個人數據是多么容易。
那么,數據泄露后會對用戶產生什么影響呢?
最直觀的體驗應該是詐騙電話,比如某些購書網站或酒店預訂網站。他們打電話給你,聲稱需要分期退款,并為了獲取你的信任,他們甚至可以告訴你你買了哪本書,預訂了哪個房間,甚至你的家庭住址和全名。
詐騙團伙能如此清楚地掌握這些信息,都是因為數據泄露。
但除了這些個人數據,還有兩樣東西可能會泄露:你的賬號和密碼。
你可能會想:“這只是一個賬號和密碼,我只要更改該網站的密碼然后再用不就行了嗎!”
事情可能并沒有你想的那么簡單。如果你沒有使用密碼管理軟件,我大膽猜測你所有的密碼可能都是相同的。因為害怕記不住,人們往往會對所有網站使用相同的密碼。
如果此時你的賬號和密碼被泄露,黑客能否嘗試在其他服務上使用這些憑證呢?
他們可以使用這些憑證登錄你的 Google 賬戶或 Facebook。使用相同密碼的人就會被黑。所以雖然最初看起來只是一個購物網站被攻破,但其后果可能導致你的 Google 和 Facebook 賬戶也被黑。
因此,有時某個網站的賬戶被黑,可能并不是因為該網站存在問題,而是黑客在其他地方獲取了你的登錄信息,并嘗試在這里使用這些信息而意外成功。
對于網站開發者來說,保護用戶數據至關重要;保護密碼也很重要。有沒有好的方法可以保護密碼呢?
加密?
使用某些算法加密密碼意味著將加密結果存儲在數據庫中,因此即使被盜,除非黑客有解密方法,否則他們無法輕易訪問。
這聽起來像是最安全的方法;然而,另一個問題隨之而來——開發人員仍然知道如何解密,這可能導致工程師濫用他們的訪問權限,了解每個用戶的實際密碼,出售信息或自己利用這些信息。
嗯……似乎我們陷入了困境,因為開發人員必須知道數據庫中存儲的確切密碼,對嗎?否則,在登錄時如何確認用戶名和密碼組合是否匹配呢?
此外,已經聽起來夠安全了,我們如何使它更安全?讓網站開發者無法解密或知道我們的實際密碼,不是應該足夠安全了嗎?
答對了!這正是需要做的!
沒有人知道你的密碼,包括網站本身
事實上,網站的數據庫并不存儲你的密碼。
更準確地說,它不存儲你的“原始密碼”,而是存儲密碼經過某種操作后的結果。最重要的是,這種操作是不可逆的。
為了給出一個直接的對比例子,假設今天有一個非常簡單的算法可以轉換密碼。轉換方法是:“數字保持不變,英文字母替換為數字(a 變成 1,b 變成 2……z 變成 26)”,以此類推。每個字母被替換為相應的數字,不區分大小寫(暫時假設沒有符號)。
如果密碼是 abc123,轉換后變成 123123。
在用戶注冊期間,網站將用戶輸入的 abc123 轉換為 123123,然后將其存儲在數據庫中。因此,數據庫中存儲的密碼是 123123,而不是 abc123。
當用戶登錄時,我們使用相同的邏輯再次轉換他們的輸入。如果轉換后匹配,那么我們不就知道密碼是正確的嗎?
黑客竊取數據庫并獲取這組密碼 123123 后,他們難道不能推斷出它最初是 abc123 嗎?不,不,不——事情沒有這么簡單。
123123,abcabc,12cab3……這些密碼散列后,不還是 123123 嗎?所以,即使你知道轉換規則和結果,也無法將其恢復為“唯一的密碼”,這是這種算法的強大之處!
這種轉換稱為散列(hash)。每次 abc123 被散列,結果總是 123123。但是,從 123123 中,你不能確定輸入必須是 abc123,因為還有其他可能性。
這就是散列與加密的最大區別。
加密和解密是一對;如果某物可以被加密,那么它也可以被解密。因此,如果你知道加密的密文和密鑰,你可以確定明文。但是使用散列,知道散列算法的結果并不能讓你反向推理出原始輸入是什么。
這種機制的最常見應用之一是安全地存儲密碼。
在注冊期間,存儲散列密碼在數據庫中。登錄時,將輸入的密碼散列并與數據庫中存儲的散列值進行比較,以驗證其正確性。即使黑客竊取數據庫中的數據,他們也不知道用戶的密碼,因為他們無法反向推理出原始密碼。
這就是為什么當你忘記密碼時,網站不會告訴你原始密碼,因為網站本身也不知道!
所以你不能“找回密碼”,只能“重置密碼”,因為重置意味著你輸入一個新密碼,然后網站將新密碼散列并存儲在數據庫中。以后登錄時,它將使用這個新散列值進行比較。
防止預先計算攻擊
一些人可能會注意到,這種存儲方法似乎有一個漏洞。繼續前面的例子,如果數據庫中存儲的是 123123,但我的原始密碼是 abc123,那么如果我使用“abcabc”,散列后也會是 123123。難道我不能這樣登錄嗎?這似乎不對;這不是我的實際密碼。
當兩個不同的輸入產生相同的輸出時,這種情況稱為碰撞(hash collision)。碰撞是不可避免的,但如果算法設計得好,碰撞非常罕見——罕見到幾乎可以忽略不計。
前面提到的轉換規則只是為了說明問題。實際使用的算法要復雜得多;即使只有一個字母的差異,結果也會大不相同。以 SHA256 為例:
abc123 => 6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090 abc124 => cd7011e7a6b27d44ce22a71a4cdfc2c47d5c67e335319ed7f6ae72cc03d7d63f
相似的輸入會產生完全不同的輸出。
前面提到的不安全散列算法的例子應該避免,或者避免自己設計算法。建議使用密碼學專家設計的算法,如上面提到的 SHA256。
使用這些算法時,還應特別注意其安全性。某些算法雖然由專家設計,但已被證明不安全。例如,使用 MD5 存儲散列密碼被認為是不安全的。
僅存儲散列值可以嗎?
對不起,僅存儲密碼的散列值是不夠的。
為什么呢?不是說結果無法逆向推理嗎?為什么這還不夠?
雖然無法逆向推理結果,但攻擊者可以利用“相同輸入總是產生相同輸出”的特性,預先構建一個包含人們數據的數據庫。
例如,假設有一個非常常見的密碼“abc123”,其散列值是“6ca13d”。攻擊者可以預先計算并將此關系存儲在他們的數據庫中。因此,攻擊者的數據庫可能包含一百萬組最常見的密碼,每組都與其對應的散列值配對。
然后,他們只需在自己的散列數據庫中搜索“6ca13d”。通過查找表,他們可以發現原始密碼是“abc123”。這種方法不涉及逆向算法;它只是使用現有數據進行查找。
為了防御這種攻擊,還需要做另一件事,叫做加鹽(salting)。是的,就像實際的鹽一樣。通常,為每個用戶生成一個唯一的鹽——例如 5ab3od(實際上會更長,可能是16個或更多字符)。然后我的密碼“abc123”會與我的鹽結合,變成“abc1235ab3od”,然后將其作為散列的輸入。
為什么要這樣做呢?
因為相比于僅使用“abc123”,找到“abc1235ab3od”在攻擊者的預計算表中可能性顯著降低。此外,增加長度使暴力破解更加困難。結果,密碼變得更難破解。
結語
當你忘記密碼時,網站不會將密碼發送給你,因為即使是網站本身也不知道你的密碼。雖然這聽起來不太可能,但事實確實如此。出于安全原因,這是一個必要的措施。
為了實現這個目標,背后最重要的技術原理是散列。“相同的密碼將生成相同的散列值,但從散列值無法反向推理出原始密碼”——這就是其中的秘密。
相反,如果你發現某個網站可以找回你的密碼,那么你應該更加謹慎,因為它可能在其數據庫中存儲了實際的密碼,而不是散列值。在這種情況下,如果有一天數據庫被黑,賬號信息包括密碼被黑客竊取,他們可以知道你的實際密碼并嘗試在其他服務上使用。
關于密碼管理,現在瀏覽器也有功能可以自動生成并記住密碼,或者你可以使用現成的密碼管理軟件,它可以為不同的網站創建不同的密碼。