Google 身份驗證器為何可以離線使用?其原理是什麼?

谷歌身份驗證的實現原理:伺服器端通過特定演算法隨機生成一個密鑰,並且把這個密鑰保存在資料庫中。根據生成的密鑰在頁面上生成一個二維碼,內容是一個 URI 地址。用戶通過掃描二維碼,把密鑰保存在客戶端。 客戶端每 30 秒使用密鑰和時間戳通過一種演算法生成一個 6 位數字的一次性 密碼。伺服器端使用保存在資料庫中的密鑰和時間戳通過同一種演算法生成一個 6 位數字的一次性密碼, 用戶登陸時輸入一次性密碼與伺服器端進行驗證,如果一 樣,就登錄成功了。谷歌賬戶兩步驗證的工作原理:Google 的兩步驗證演算法源自另一種名為 HMAC-Based One-Time Password 的 演算法,簡稱 HOTP。HOTP 的工作原理如下: 客戶端和伺服器事先協商好一個密鑰 K,用於一次性密碼的生成過程,此密 鑰不被任何第三方所知道。此外客戶端和伺服器端各有一個計數器 C,並且事先 將計數值同步。進行驗證時,客戶端對密鑰和計數器的組合合(K,C)使用 HMAC(Hash-based Message Authentication Code)演算法計算一次性密碼,公式如下: HOTP(K,C) = Truncate(HMAC-SHA-1(K,C)) 上面採用了 HMAC-SHA-1,當然也可以使用 HMAC-MD5 等。HMAC 演算法得出 的值位數比較多,不方便用戶輸入,因此需要截斷(Truncate)成為一組不太長 十進位數(例如 6 位) 。計算完成之後客戶端計數器 C 計數值加 1。用戶將這一 組十進位數輸入並且提交之後, 伺服器端同樣的計算,並且與用戶提交的數值比 較,如果相同,則驗證通過,伺服器端將計數值 C 增加 1。如果不相同,則驗證失敗。


我特么看完問題突然發現,媽蛋,這是問題嗎?


原理篇:我們往往會在不同的網站上使用相同的密碼,這樣一旦一個網站賬戶的密碼泄露,就會危及到其他使用相同密碼的賬戶的安全,這也是最近的密碼泄露事件造成如此大影響的原因。為了解決這個問題,一些網站在登錄時要求除了輸入賬戶密碼之外,還需要輸入另一個一次性密碼。銀行常用的動態口令卡就是這種一次性密碼的例子,在線支付網站的一次性簡訊密碼則是另一種實現。

Google現在也推薦用戶啟用兩步驗證(Two-step verification)功能(Youtube上的視頻介紹),並且除了以簡訊或者電話的方式發送一次性密碼之外,還提供了另一種基於時間的一次性密碼(Time-based One-time Password,簡稱TOTP),只需要在手機上安裝密碼生成應用程序,就可以生成一個隨著時間變化的一次性密碼,用於帳戶驗證,而且這個應用程序不需要連接網路即可工作。仔細看了看這個方案的實現原理,發現挺有意思的。下面簡單介紹一下。

HTOPGoogle的兩步驗證演算法源自另一種名為HMAC-Based One-Time Password的演算法,簡稱HOTP。HOTP的工作原理如下:

客戶端和伺服器事先協商好一個密鑰K,用於一次性密碼的生成過程,此密鑰不被任何第三方所知道。此外,客戶端和伺服器各有一個計數器C,並且事先將計數值同步。

進行驗證時,客戶端對密鑰和計數器的組合(K,C)使用HMAC(Hash-based Message Authentication Code)演算法計算一次性密碼,公式如下:

HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

上面採用了HMAC-SHA-1,當然也可以使用HMAC-MD5等。HMAC演算法得出的值位數比較多,不方便用戶輸入,因此需要截斷(Truncate)成為一組不太長十進位數(例如6位)。計算完成之後客戶端計數器C計數值加1。用戶將這一組十進位數輸入並且提交之後,伺服器端同樣的計算,並且與用戶提交的數值比較,如果相同,則驗證通過,伺服器端將計數值C增加1。如果不相同,則驗證失敗。

這裡的一個比較有趣的問題是,如果驗證失敗或者客戶端不小心多進行了一次生成密碼操作,那麼伺服器和客戶端之間的計數器C將不再同步,因此需要有一個重新同步(Resynchronization)的機制。這裡不作具體介紹,詳情可以參看RFC 4226。

TOTP介紹完了HOTP,Time-based One-time Password(TOTP)也就容易理解了。TOTP將HOTP中的計數器C用當前時間T來替代,於是就得到了隨著時間變化的一次性密碼。非常有趣吧!

雖然原理很簡單,但是用時間來替代計數器會有一些特殊的問題,這些問題也很有意思,我們選取幾個進行一下探討。

首先,時間T的值怎麼選取?因為時間每時每刻都在變化,如果選擇一個變化太快的T(例如從某一時間點開始的秒數),那麼用戶來不及輸入密碼。如果選擇一個變化太慢的T(例如從某一時間點開始的小時數),那麼第三方攻擊者就有充足的時間去嘗試所有可能的一次性密碼(試想6位數字的一次性密碼僅僅有10^6種組合),降低了密碼的安全性。除此之外,變化太慢的T還會導致另一個問題。如果用戶需要在短時間內兩次登錄賬戶,由於密碼是一次性的不可重用,用戶必須等到下一個一次性密碼被生成時才能登錄,這意味著最多需要等待59分59秒!這顯然不可接受。綜合以上考慮,Google選擇了30秒作為時間片,T的數值為從Unix epoch(1970年1月1日 00:00:00)來經歷的30秒的個數。

第二個問題是,由於網路延時,用戶輸入延遲等因素,可能當伺服器端接收到一次性密碼時,T的數值已經改變,這樣就會導致伺服器計算的一次性密碼值與用戶輸入的不同,驗證失敗。解決這個問題個一個方法是,伺服器計算當前時間片以及前面的n個時間片內的一次性密碼值,只要其中有一個與用戶輸入的密碼相同,則驗證通過。當然,n不能太大,否則會降低安全性。

事實上,這個方法還有一個另外的功能。我們知道如果客戶端和伺服器的時鐘有偏差,會造成與上面類似的問題,也就是客戶端生成的密碼和服務端生成的密碼不一致。但是,如果伺服器通過計算前n個時間片的密碼並且成功驗證之後,伺服器就知道了客戶端的時鐘偏差。因此,下一次驗證時,伺服器就可以直接將偏差考慮在內進行計算,而不需要進行n次計算。

以上就是Google兩步驗證的工作原理,推薦大家使用,這確實是保護帳戶安全的利器。

參考資料

  • TOTP: Time-based One-time Password Algorithm, RFC Draft, TOTP: Time-based One-time Password Algorithm
  • HOTP: An HMAC-Based One-Time Password Algorithm, RFC 4226, RFC 4226 - HOTP: An HMAC-Based One-Time Password Algorithm
  • Google Authenticator project, google-authenticator -

    Two-step verification

實現篇:實現Google Authenticator功能需要伺服器端和客戶端的支持。伺服器端負責密鑰的生成、驗證一次性密碼是否正確。客戶端記錄密鑰後生成一次性密碼。

目前客戶端有:

  • android版: Google 身份驗證器
  • iOS版:iTunes 的 App Store 中的「Google Authenticator」

用戶需要開啟Google Authenticator服務時1.伺服器隨機生成一個類似於『DPI45HKISEXU6HG7』的密鑰,並且把這個密鑰保存在資料庫中。

2.在頁面上顯示一個二維碼,內容是一個URI地址(otpauth://totp/賬號?secret=密鑰),如『otpauth://totp/kisexu@gmail.com?secret=DPI45HCEBCJK6HG7』

3.客戶端掃描二維碼,把密鑰『DPI45HKISEXU6HG7』保存在客戶端。

用戶需要登陸時1.客戶端每30秒使用密鑰『DPI45HKISEXU6HG7』和時間戳通過一種『演算法』生成一個6位數字的一次性密碼,如『684060』。如下圖android版界面:

2.用戶登陸時輸入一次性密碼『684060』。

3.伺服器端使用保存在資料庫中的密鑰『DPI45HKISEXU6HG7』和時間戳通過同一種『演算法』生成一個6位數字的一次性密碼。大家都懂控制變數法,如果演算法相同、密鑰相同,又是同一個時間(時間戳相同),那麼客戶端和伺服器計算出的一次性密碼是一樣的。伺服器驗證時如果一樣,就登錄成功了。

Tips:1.這種『演算法』是公開的,所以伺服器端也有很多開源的實現,比如php版的:PHPGangsta/GoogleAuthenticator · GitHub 。上github搜索『Google Authenticator』可以找到更多語言版的Google Authenticator。

2.所以,你在自己的項目可以輕鬆加入對Google Authenticator的支持,在一個客戶端上顯示多個賬戶的效果可以看上面android版界面的截圖。目前dropbox、lastpass、wordpress,甚至vps等第三方應用都支持Google Authenticator登陸,請自行搜索。

3.現實生活中,網銀、網路遊戲的實體動態口令牌其實原理也差不多


題主你要科普也沒必要這樣自問自答塞,讓我們知乎網友想回答都冇的機會


知乎秒變博客的節奏..


這樣完善的自問自答,只要默默關注就好了


題主來科普的!


自問自答?


推薦閱讀:

怎麼看待「做Android就是做界面」這種觀點?
外國人用哪些便宜的安卓手機?性能有中國的好嗎?
為什麼 iOS 撥號數字用橫線間隔,而原生 Android 撥號用空格間隔?
手機撥打電話的時候,當你的耳朵貼近手機的時候,手機屏幕會進入休眠狀,一旦手機拿開自己的耳朵,又變亮了,這個是怎麼一回事?
為什麼小米手機國行被禁止內置 Google 服務框架,三星 S8 國行卻可以?

TAG:互聯網 | 信息安全 | 谷歌Google | Android | 身份驗證 |