使用 Go 構建基於時間的一次性密碼 -TOTP- 生成器
前言
現在很多網站都開啓了 2FA(Two-Factor Authentication,雙因素認證),如 GitHub、Google、微軟等。這種額外的安全層顯著提高了賬戶的安全性。本文將深入探討如何使用 Go 語言實現 TOTP 生成器,並詳細解釋其工作原理和安全考慮
原理解析
兩步驗證要求用戶提供兩種不同形式的身份驗證:
-
知識因素:用戶知道的信息(如密碼)
-
所有權因素:用戶擁有的設備(如手機)
-
生物特徵因素:用戶的生物特徵(如指紋)
使用 2FA 可以大大增加賬戶的安全性,因爲即使攻擊者獲取了用戶的密碼,沒有第二個驗證因素,他們也無法訪問賬戶.
- TOTP 技術原理
基於時間的一次性密碼(Time-based One-Time Password,TOTP)是 HOTP(基於事件的一次性密碼)的一種變種,它引入了時間作爲動態因素。 TOTP 算法使用一個祕密密鑰和當前時間來生成一次性密碼。這個密碼每 30 秒(或者配置的其他時間段)就會變化,因此即便泄露,效用也很短暫。
TOTP 遵循 RFC 6238 標準,並且通常用於實現 2FA。每個 TOTP 都是通過以下步驟生成的:
-
取得當前時間戳。
-
將時間戳向下取整到最接近的 30 秒間隔(這是默認的時間步長,但可以調整)。
-
對這個時間值應用 HMAC-SHA1 算法,使用預先共享的祕密密鑰作爲密鑰。
-
對 HMAC 結果進行動態截斷以得到一個固定長度的數字串(通常是 6 位數)。
-
將這個數字串作爲一次性密碼。
- TOTP 工作流程詳解
-
客戶端和服務端共享一個密鑰(通常通過二維碼生成並掃描)。
-
使用 HMAC-SHA1 算法計算哈希值。
-
將時間戳與共享密鑰結合,生成動態密碼。
-
服務端驗證生成的密碼是否匹配。
-
如果匹配,則允許用戶登錄。
實現 TOTP 生成器
基礎設置
Go 語言中可以使用 github.com/pquerna/otp 庫來實現 TOTP
package main
import (
"github.com/pquerna/otp/totp"
"github.com/skip2/go-qrcode"
)
核心功能實現
- 服務端生成 TOTP 密鑰,並將其以 URI 格式返回給客戶端,客戶端可以使用此 URI 生成 TOTP 密碼。
package main
import (
"fmt"
"log"
"time"
"github.com/pquerna/otp/totp"
)
func main() {
// 生成共享密鑰
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "Github",
AccountName: "pfinal@pfinalclub.top",
})
if err != nil {
log.Fatalf("Failed to generate TOTP key: %v", err)
}
fmt.Println("Generated TOTP Key URI:")
fmt.Println(key.URL())
// 獲取當前時間戳生成的 TOTP
code, err := totp.GenerateCode(key.Secret(), time.Now())
if err != nil {
log.Fatalf("Failed to generate TOTP code: %v", err)
}
fmt.Printf("Generated TOTP Code: %s\n", code)
// 驗證 TOTP
isValid := totp.Validate(code, key.Secret())
if isValid {
fmt.Println("TOTP Code is valid!")
} else {
fmt.Println("Invalid TOTP Code.")
}
}
代碼詳解:
-
生成密鑰 totp.Generate 方法生成一個共享密鑰,可以通過二維碼或文本形式分發給用戶。
-
生成動態密碼 使用 totp.GenerateCode 方法,將共享密鑰和當前時間戳結合,生成 6 位動態密碼。
-
驗證密碼 totp.Validate 方法通過對比用戶輸入的動態密碼和服務端生成的密碼進行驗證。
- 或者生成二維碼供用戶掃描
import (
"os"
"github.com/pquerna/otp/totp"
"github.com/skip2/go-qrcode"
)
func generateQRCode(key *totp.Key) {
qrCode, _ := qrcode.New(key.URL(), qrcode.Medium)
qrCode.WriteFile(256, "qrcode.png")
fmt.Println("QR Code generated: qrcode.png")
}
- 有時候 由於網絡等原因 服務器和客戶端時間 不同步 可以設置一個時間偏移量 使用 totp.ValidateCustom 方法,設置寬容時間窗口
isValid := totp.ValidateCustom(code, key.Secret(), time.Now(), totp.ValidateOpts{
Skew: 1, // 寬容時間窗口
})
安全性考慮
在實現和部署兩步驗證(2FA)系統時,有多個方面需要考慮以確保系統的安全性和用戶體驗。以下是需要注意的一些關鍵點
-
密鑰安全:密鑰應該是隨機生成的,並且在傳輸和存儲過程中保持安全。密鑰泄露可能導致 TOTP 碼被惡意使用。
-
時間同步:服務器和客戶端的時間應該保持同步,以確保生成的 TOTP 碼的正確性。時間差異可能導致驗證失敗。
-
重放攻擊:攻擊者可能嘗試重放已經使用過的 TOTP 碼,以繞過驗證。爲了防止重放攻擊,可以使用一次性密碼或者時間戳來確保每個 TOTP 碼只能使用一次。
-
密碼長度:TOTP 碼的長度應該足夠長,以防止暴力破解。建議使用至少 6 位數的 TOTP 碼。
-
密碼有效期:TOTP 碼應該有一個有效期限,以防止攻擊者在有效期內多次嘗試。建議使用短期的有效期限,如 30 秒。
-
密碼存儲:TOTP 碼不應該以明文形式存儲,以防止數據泄露。可以使用加密算法對 TOTP 碼進行加密存儲。
-
密鑰更新:密鑰應該定期更新
總結
使用 Go 語言構建 TOTP 生成器不僅能夠提供強大的安全保護,還能確保良好的用戶體驗。通過遵循安全最佳實踐並實現適當的錯誤處理,我們可以創建一個可靠的雙因素認證解決方案。
記住,安全性是一個持續的過程,定期更新和維護你的實現以應對新的安全挑戰是很重要的。通過適當的規劃和實現,TOTP 可以顯著提高你的應用程序的安全性。
參考資源
-
RFC 6238 (TOTP 標準)
-
GitHub Security Best Practices
-
Go 加密庫文檔
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/SuyUHi08BdnchaC8KQ0F3Q?poc_token=HFpZd2ejoHgH-xpL6trR7MtrRp7a5bgVyY16U2Gg