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