image from Twilio

只要十分鐘,帶你看懂 TOTP 2FA 的密碼學原理

Larry Lu
Starbugs Weekly 星巴哥技術專欄
9 min readJun 12, 2022

--

身為一個工程師,為了提高安全性,應該都會幫自己還有公司的帳號啟用 2FATwo-Factor Authentication),不然帳號被盜是真的會出大事。

像去年就有一個案例是,npm 上有一個超熱門的 package 叫 UAParser.js 用來解析 User Agent 是什麼瀏覽器,每個禮拜的下載次數都接近一千萬。但去年作者的帳號被盜了之後,駭客在 npm 上發佈了好幾個含有挖礦程式的版本,造成不小的轟動,還好很快就發現了並且把那些版本撤銷掉。

所以說密碼真的要保管好,而且重要的服務像 Github、Google、Facebook 的帳號最好都上 2FA,才不會 Facebook 被盜,連帶用 Facebook 登入的 Instagram、蝦皮也被盜,那處理起來就真的很麻煩

Two-Factor Authentication

今天的主題是 2FATwo-Factor Authentication)。這邊簡單介紹一下 ,一般來說我們都是使用帳號密碼來驗證身份,而 2FA 就是建立除了帳號密碼之外的第二個關卡。就算帳密不小心外洩了,也不至於馬上被盜用(但還是要定期改密碼啦XD)。而 2FA 又可以分成硬體跟軟體兩種形式

硬體型 2FA

像在 App Store 上買 App 時需要指紋辨識,或是前陣子很紅的 YubiKey,只有把那隻隨身碟帶在身上才能通過驗證,都算是硬體型的 2FA。

軟體型 2FA

而今天要講的 OTPOne-Time Password) 就是軟體型的 2FA。像大部分銀行在 App 轉帳時都會要求你輸入「簡訊驗證碼」、或是當你要從新電腦登入 Google 時,也會需要到手機上打開 Gmail 看驗證碼,這些都算是。

因為這些驗證碼每次都不一樣,所以我們把它稱為 One-Time 也就是一次性的 Password,每次都不一樣自然安全性也比較高。

所以像這樣用手機收簡訊驗證碼有什麼不好嗎?

雖然簡訊驗證碼每次都是隨機的,但其實簡訊在傳輸的過程中非常不安全。撇開簡訊不談,就算驗證碼是用 App、電子郵件來傳輸,只要每次你登入時,服務提供者試圖把驗證碼「傳」給你,那就有遭竊的可能。

ㄜ⋯⋯如果我登入時對方不把驗證碼「傳」給我,那我要怎麽拿到驗證碼?

雖然聽起來很神奇,但確實是可以靠密碼學做到的哦,那就是今天要介紹的主角 TOTP

Time-based One Time Password

TOTP 的全名是 Time-based One Time Password,看名字就知道他也是 OTP 的一種,只不過是藉由目前的時間來生出 OTP,因此天生就具有隨機性。因為直接看公式太硬了,這邊我用 Github 2FA 的例子來講解他的運作原理

如果你的 Github 還沒啟用 2FA 的話,可以跟著官方文件先設定好,等等看下面的講解才知道每個步驟在做什麼哦~

Step 1 — Server 生成帶有 secret key 的 QRCode

通常要啟用 TOTP 2FA 的第一步,都會讓你掃一個大大的 QRCode,而這個 QRCode 中就帶有 server 想要傳給你的 secret key

如果把上圖的 QRCode decode 出來會得到 otpauth://totp/GitHub:LarryLuTW?secret=X5CTBOMEYE3TXIIS 這一串鬼東西,意思是這串 URI 是由 Github 發行的,而後面的 secret=X5CTBOMEYE3TXIIS 就是 Github 想要傳給你的 secret key

因此當你用手機上的 Authentication App 去掃描時(我是用 Authy,還有很多其他 App 可以選),App 就會把這串 secret 存起來,以後就用這個 secret 生成 TOTP

Step 2 — 驗證兩邊生成相同的 TOTP

有了這串 secret 之後 App 要怎麼生出下面六碼 OTP 呢?答案就是把 secret現在時間 拿去做雜湊,然後取最後的六碼作為 OTP

如果不知道雜湊是什麼,可以先去看看我另外一篇「一次搞懂密碼學中的三兄弟」,再回來讀會比較順哦

譬如說我現在時間換算成 UNIX timestamp1654994758(也就是從 1970 年 1 月 1 號,已經過了這麼多秒),然後 secret 是 X5CTBOMEYE3TXIIS

因為 App 希望每 30 秒產生出不同的 OTP,所以他會把 timestamp/30 的整數部分跟 X5CTBOMEYE3TXIIS 這兩個東西丟進去 HMAC 做雜湊,雜湊的結果轉成十進位取最後六碼,就可以得到這 30 秒的 OTP 是 017201 了~

而 30 秒後因為 timestamp/30 的結果又不一樣了,所以又會生出完全不同的 OTP(只要輸入值稍有不同,hash 的結果就會完全不一樣)

有了這六位數 OTP 後,你就在三十秒內到網站輸入 017201(三十秒後又是不同的 OTP)。如果 Github 那邊剛好也算出跟你一模一樣的結果,那他就知道你已經拿到正確 secret key。從此之後你跟 Github 就算是約定好 secret 了,Github 也會把這 secret 存在他們自家的資料庫裡面,

Step 3 — 登入時驗證 TOTP

設定好 2FA 後,以後你要登入時,Github 就會請你輸入 App 生出來的 OTP

因為雙方已經溝通好 secret 是 X5CTBOMEYE3TXIIS 了,這時你用不著收簡訊,甚至可以不需要網路,只要把 App 打開它就會幫你算出新的 OTP

而 Github 收到你輸入的 OTP 後,如果他那邊也算出一樣的結果,那就代表你是本人。如此一來,就實現了「每次登入時 Github 不用傳驗證碼給你,但你卻可以知道驗證碼

安全性分析

總歸來說,使用 TOTP 來進行 2FA 的第一步就是藉由 QRCode 讓 Server 跟 Client(也就是 App)約定好一個 secret,之後就都用那個 secret 跟當下時間來進行 Hash。我們就按這個流程來評估每個步驟的安全性

secret 的傳輸安全嗎?

一開始要設定 TOTP 2FA 時 Github 會生出一個 QRCode 讓你掃,其中就帶有他想要給你的 secret key。如果這個 secret 在傳輸的過程中一不小心被駭客偷走,那他日後就可以用這個 secret 生出登入所需的 OTP

因此在設定 TOTP 時一定要記得檢查網站是否有 HTTPS 或是憑證過期的問題,或是看看有沒有人在你背後偷掃你的 QRCode。如果都沒有,那恭喜你!世界上應該只有你跟 Github 知道這組 secret,因此非常的安全

放 secret 的地方安全嗎?

App 收到 secret key 幫你存起來後,接下來要考慮的就是 App 安全嗎?譬如說他會不會偷偷把你的 secret 拿去賣錢,或是他有沒有支援雲端備份的功能,一不小心就會外洩出去。

像我自己用的 Authy 就有支援雲端備份,但我是不怕 secret 不見,也不太擔心手機突然爆掉,所以就沒有啟用。大家可以根據自己的情況去評估看看

OTP 會不會被猜到

如果駭客拿不到 secret,那他能不能暴力破解猜到六位數的 OTP 呢?這邊簡單試算一下:因為 OTP 有六位數所以有 一百萬 種可能性,而且每 30 秒就換一個。如果你想要在 30 秒內猜出來,那每秒就需要進行超過 三萬 次登入

但實際上只要連續失敗個幾次,Github 就會暫時把你擋下來(其他網站也是),而你下次要試的時候驗證碼又不一樣了,所以完全不可能暴力破解

因此總的來說,除非你的 secret key 一開始就被偷走,不然使用 TOTP 來做 2FA 絕對是足夠安全的

總結

好久沒有寫密碼學相關的東西了。這次介紹的 TOTP 2FA 除了原理簡單、安全性高之外,我個人覺得最方便的就是 TOTP 是在我手機上產生的、打開 App 就能看到,所以終於不會再收不到簡訊了XDD

尤其我之前住在台北市的邊陲地帶,簡訊要重送個兩三次才會送到,有時候甚至會一次來兩則,害我一不小心又輸入錯,拜託我只是想登入而已啊!!是有這麼困難嗎?

至於要用哪個 App,我個人是覺得 Authy 不錯,不過大家也可以看看 The Best 2FA Apps 2022 評估一下,選一款最適合自己的~

延伸閱讀

--

--

Larry Lu
Starbugs Weekly 星巴哥技術專欄

我是 Larry 盧承億,傳說中的 0.1 倍工程師。我熱愛技術、喜歡與人分享,專長是 JS 跟 Go,平常會寫寫技術文章還有參加各種技術活動,歡迎大家來找我聊聊~