雙因素認證(2FA)教程

阮一峰發表於2017-11-02

所謂認證(authentication)就是確認使用者的身份,是網站登入必不可少的步驟。

密碼是最常見的認證方法,但是不安全,容易洩露和冒充。

越來越多的地方,要求啟用雙因素認證(Two-factor authentication,簡稱 2FA)。本文介紹它的概念和實現方法。

文章結尾有一則活動訊息優達學城(Udacity)的"雙十一優惠",課程最高減免1111元。

一、雙因素認證的概念

一般來說,三種不同型別的證據,可以證明一個人的身份。

  • 祕密資訊:只有該使用者知道、其他人不知道的某種資訊,比如密碼。
  • 個人物品:該使用者的私人物品,比如身份證、鑰匙。
  • 生理特徵:該使用者的遺傳特徵,比如指紋、相貌、虹膜等等。

這些證據就稱為三種"因素"(factor)。因素越多,證明力就越強,身份就越可靠。

雙因素認證就是指,通過認證同時需要兩個因素的證據。

銀行卡就是最常見的雙因素認證。使用者必須同時提供銀行卡和密碼,才能取到現金。

二、雙因素認證方案

常用的雙因素組合是密碼 + 某種個人物品,比如網上銀行的 U 盾。使用者插上 U 盾,再輸入密碼,才能登入網上銀行。

但是,使用者不可能隨時攜帶 U 盾,手機才是最好的替代品。密碼 + 手機就成了最佳的雙因素認證方案。

國內的很多網站要求,使用者輸入密碼時,還要提供短訊息傳送的驗證碼,以證明使用者確實擁有該手機。

但是,短訊息是不安全的,容易被攔截和偽造,SIM 卡也可以克隆。已經有案例,先偽造身份證,再申請一模一樣的手機號碼,把錢轉走。

因此,安全的雙因素認證不是密碼 + 短訊息,而是下面要介紹的 TOTP

三、TOTP 的概念

TOTP 的全稱是"基於時間的一次性密碼"(Time-based One-time Password)。它是公認的可靠解決方案,已經寫入國際標準 RFC6238

它的步驟如下。

第一步,使用者開啟雙因素認證後,伺服器生成一個金鑰。

第二步:伺服器提示使用者掃描二維碼(或者使用其他方式),把金鑰儲存到使用者的手機。也就是說,伺服器和使用者的手機,現在都有了同一把金鑰。

注意,金鑰必須跟手機繫結。一旦使用者更換手機,就必須生成全新的金鑰。

第三步,使用者登入時,手機客戶端使用這個金鑰和當前時間戳,生成一個雜湊,有效期預設為30秒。使用者在有效期內,把這個雜湊提交給伺服器。

第四步,伺服器也使用金鑰和當前時間戳,生成一個雜湊,跟使用者提交的雜湊比對。只要兩者不一致,就拒絕登入。

五、TOTP 的演算法

仔細看上面的步驟,你可能會有一個問題:手機客戶端和伺服器,如何保證30秒期間都得到同一個雜湊呢?

答案就是下面的公式。


TC = floor((unixtime(now) − unixtime(T0)) / TS)

上面的公式中,TC 表示一個時間計數器,unixtime(now)是當前 Unix 時間戳,unixtime(T0)是約定的起始時間點的時間戳,預設是0,也就是1970年1月1日。TS 則是雜湊有效期的時間長度,預設是30秒。因此,上面的公式就變成下面的形式。


TC = floor(unixtime(now) / 30)

所以,只要在 30 秒以內,TC 的值都是一樣的。前提是伺服器和手機的時間必須同步。

接下來,就可以算出雜湊了。


TOTP = HASH(SecretKey, TC)

上面程式碼中,HASH就是約定的雜湊函式,預設是 SHA-1。

TOTP 有硬體生成器和軟體生成器之分,都是採用上面的演算法。

(說明:TOTP 硬體生成器)

(說明:Google Authenticator 是一個生成 TOTP 的手機 App)

五、TOTP 的實現

TOTP 很容易寫,各個語言都有實現。下面我用 JavaScript 實現2fa來演示一下真實程式碼。

首先,安裝這個模組。


$ npm install --save 2fa

然後,生成一個32位字元的金鑰。


var tfa = require('2fa');

tfa.generateKey(32, function(err, key) {
  console.log(key);
});
// b5jjo0cz87d66mhwa9azplhxiao18zlx

現在就可以生成雜湊了。


var tc = Math.floor(Date.now() / 1000 / 30);
var totp = tfa.generateCode(key, tc);
console.log(totp); // 683464

六、總結

雙因素認證的優點在於,比單純的密碼登入安全得多。就算密碼洩露,只要手機還在,賬戶就是安全的。各種密碼破解方法,都對雙因素認證無效。

缺點在於,登入多了一步,費時且麻煩,使用者會感到不耐煩。而且,它也不意味著賬戶的絕對安全,入侵者依然可以通過盜取 cookie 或 token,劫持整個對話(session)。

雙因素認證還有一個最大的問題,那就是帳戶的恢復。

一旦忘記密碼或者遺失手機,想要恢復登入,勢必就要繞過雙因素認證,這就形成了一個安全漏洞。除非準備兩套雙因素認證,一套用來登入,另一套用來恢復賬戶。

七、參考連結

(正文完)

====================================

從業兩三年後,程式設計師往往遇到職業瓶頸,80%的人都把時間耗費在熬夜加班、修 Bug,只有少數人選擇業餘時間精進技術,提升自己的潛力,突破薪資天花板。

優達學城(Udacity)作為來自矽谷的前沿技術學習平臺,幫你掌握前沿技術。

它的課程和專案,來自Google、Facebook等矽谷名企,並提供人工審閱、一對一線上答疑等服務,拒絕浪費時間走彎路。

今年雙十一,與其囤積一年都用不完的便宜貨,不如來優達學城投資未來提升自我。11月1日~11月11日,課程全場最高減¥1111,讓你輕鬆享有矽谷學習資源!

優惠席位有限,先到先得,點選這裡瞭解詳情。

(完)

相關文章