從今年(2023)三月份開始,Github開始強制用戶開啟兩步驗證2FA(雙因數)登錄驗證,毫無疑問,是出於安全層面的考慮,畢竟Github賬號一旦被盜,所有代碼倉庫都會毀於一旦,關於雙因數登錄的必要性請參見:別讓你的伺服器(vps)淪為肉雞(ssh暴力破解),密鑰驗證、雙向因數登錄值得擁有。 雙因 ...
從今年(2023)三月份開始,Github開始強制用戶開啟兩步驗證2FA(雙因數)登錄驗證,毫無疑問,是出於安全層面的考慮,畢竟Github賬號一旦被盜,所有代碼倉庫都會毀於一旦,關於雙因數登錄的必要性請參見:別讓你的伺服器(vps)淪為肉雞(ssh暴力破解),密鑰驗證、雙向因數登錄值得擁有。
雙因數登錄說白了就是通過第三方設備證明"你是你自己"的一個措施,Github官方推薦在移動端下載1Password、Authy、Microsoft Authenticator等APP來通過掃碼進行驗證,其實大可不必如此麻煩,本次我們通過Python/Golang代碼來實現雙因數登錄驗證。
TOTP演算法
Time-based One-Time Password(TOTP)是一種基於時間的一次性密碼演算法,用於增強身份驗證的安全性。
TOTP基於HMAC(Hash-based Message Authentication Code)演算法和時間戳生成一次性密碼。用戶和伺服器之間共用一個密鑰,通常在初始化身份驗證時交換。基於該密鑰,伺服器生成一個用於驗證的初始值。
在每個時間步長(通常是30秒),基於當前時間戳和共用密鑰,使用HMAC演算法生成一個哈希值。然後,從哈希值中提取一個固定長度的動態密碼。這個動態密碼在設定的時間步長內有效,之後會自動失效。
用戶在進行身份驗證時,需要輸入當前時間步長內生成的動態密碼。伺服器會使用相同的演算法和共用密鑰,驗證用戶提供的密碼是否匹配。由於動態密碼在時間步長過期後就會失效,即使被截獲,也無法在下一個時間步長內重覆使用。
TOTP廣泛應用於雙因素身份驗證(2FA)和多因素身份驗證(MFA)的實現中。通過結合用戶的密碼和每次生成的動態密碼,TOTP提供了一層額外的安全保護,有效降低了密碼被盜用或猜測的風險。
常見的TOTP應用包括Google Authenticator和Authy等身份驗證應用程式,它們生成基於TOTP演算法的動態密碼,並與用戶的線上賬戶相綁定,提供更安全的登錄方式。
說白了,就是一個帶生命周期的密鑰,30秒之後這個密鑰就會過期,客戶端和服務端共用一個密鑰,通過HMAC演算法來驗證密鑰的合法性。
TOTP演算法實現(Python3.10)
首先在服務端應該先生成一個密鑰,該密鑰在客戶端和認證伺服器之間共用。密鑰可以是字元串,但Github官方把該密鑰弄成了二維碼,以方便用戶在移動端掃碼驗證,打開Github賬戶,選擇設置-》兩步驗證:
點擊綠色按鈕,選擇開啟兩步驗證。
此時系統會自動生成一個二維碼,這就是我們共用的密鑰:
該密鑰的字元串形式可以通過點擊setup key超鏈接來獲取。
拿到系統密鑰之後,我們安裝基於Python的TOTP庫:
pip3 install pyotp
隨後編寫代碼生成當前時序的驗證碼:
import pyotp
import time
# 設置服務端密鑰
secret_key = "Github服務端生成的密鑰(即二維碼)"
# 使用密鑰和時間間隔(預設為 30 秒)創建一個 TOTP 對象
totp = pyotp.TOTP(secret_key)
# 生成當前的 OTP
current_otp = totp.now()
print(f"當前OTP: {current_otp}")
運行結果:
python -u "d:\jiyun\積雲\boo3_public\test_totp.py"
當前OTP: 809888
可以看到根據密鑰我們生成了30秒以內有效期的驗證碼,隨後將該驗證碼填入頁面中的Verify the code from the app文本框即可。簡單方便,並不需要移動端的參與。
Golang1.21實現TOTP演算法
如果客戶端的語言是Golang,也可以輕鬆實現TOTP演算法,首先確保本機安裝Golang1.18以上的版本,這裡我們使用的是最新的Golang1.21:
PS C:\Users\zcxey> go version
go version go1.21.1 windows/amd64
隨後通過go get安裝對應的totp包:
go get github.com/pquerna/otp
go get github.com/pquerna/otp/totp
接著編寫入口代碼main.go文件:
package main
import (
"encoding/base32"
"fmt"
"time"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
)
// Demo function, not used in main
// Generates Passcode using a UTF-8 (not base32) secret and custom parameters
func GeneratePassCode(utf8string string) string {
secret := base32.StdEncoding.EncodeToString([]byte(utf8string))
passcode, err := totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{
Period: 30,
Skew: 1,
Digits: otp.DigitsSix,
Algorithm: otp.AlgorithmSHA512,
})
if err != nil {
panic(err)
}
return passcode
}
func main() {
passcode := GeneratePassCode("Github官方生成的密鑰")
fmt.Print(passcode)
}
這裡通過GeneratePassCode函數來生成驗證碼,預設有效期同樣是30秒,演算法基於otp.AlgorithmSHA512。
運行結果:
go run "d:\jiyun\積雲\boo3_public\main.go"
692540
隨後同樣將該驗證碼填入頁面中的Verify the code from the app文本框即可。和Python不同的是,Golang直接編譯好以後可以在任意平臺直接運行,理論上要比Python要方便的多。
結語
總體而言,GitHub的雙因數登錄提供了更高的賬戶安全性,保護用戶免受未經授權的訪問和潛在的數據泄露。它是一種簡單而有效的安全措施,值得用戶採取以保護他們的GitHub賬戶和相關代碼資產,不過話說回來,Github官方力推收費的1Password軟體,應該是有一些利益上的綁定,但對於會代碼的我們來說,這都不算事兒。