A07: 身分驗證與授權失敗(Identification and Authentication Failures)
漏洞概述
身分驗證失敗主要發生在應用程式未能正確管理使用者身份驗證機制,導致攻擊者能夠繞過身份驗證、冒充合法用戶或執行未經授權的操作。常見的身分驗證問題包括:
- 弱密碼與暴力破解攻擊
- 缺乏帳號鎖定機制
- JWT(JSON Web Token)驗證失敗
- 憑證重放攻擊(Replay Attack)
- 多因素驗證(MFA)未實施
攻擊者可以利用這些漏洞進行帳號劫持、未經授權的存取,甚至進一步提升 權限,造成嚴重的資安風險。
🔍 問題分析
1. 弱密碼與暴力破解攻擊
應用程式允許使用簡單、常見的密碼(如 password123
),使攻擊者能夠透過字典攻擊或暴力破解來猜測密碼,進而登入系統。
❌ 攻擊方式:
- 使用工具(如 Hydra、Burp Suite)進行暴力破解攻擊。
- 嘗試常見密碼清單,如
admin/admin
、123456
、password
等。
❌ 示範程式碼(Golang 範例)
package main
import (
"fmt"
"log"
"net/http"
)
var validUsers = map[string]string{
"admin": "password123", // 弱密碼
}
func loginHandler(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("username")
password := r.FormValue("password")
if validUsers[username] == password {
fmt.Fprintf(w, "登入成功!")
} else {
http.Error(w, "登入失敗", http.StatusUnauthorized)
}
}
func main() {
http.HandleFunc("/login", loginHandler)
fmt.Println("伺服器啟動於 http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
✅ 修補措施
- 強制使用強密碼(長度、複雜度、特殊符號)
- 使用密碼雜湊(如 bcrypt)存儲密碼
- 實施帳號鎖定機制(連續登入失敗後鎖定帳號)
- 使用 CAPTCHA 來防止機器人攻擊
2. JWT 驗證失敗
JWT 是一種無狀態的身份驗證機制,但若密鑰管理不當,攻擊者可以偽造 JWT,繞過身份驗證,或使用 none
算法來完全取消驗證。
❌ 攻擊方式
- 使用工具(如 jwt_tool)更改 JWT 內容,例如更改
user:admin
- 若應用接受
none
作為簽名演算法,攻擊者可以偽造一個 JWT,繞過驗證
❌ 示範程式碼(Golang 範例)
package main
import (
"fmt"
"log"
"net/http"
"github.com/dgrijalva/jwt-go"
)
var mySigningKey = []byte("weaksecret") // 弱密鑰
func loginHandler(w http.ResponseWriter, r *http.Request) {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["username"] = "admin"
tokenString, err := token.SignedString(mySigningKey)
if err != nil {
http.Error(w, "無法建立 token", http.StatusInternalServerError)
return
}
w.Header().Set("Authorization", "Bearer "+tokenString)
fmt.Fprintf(w, "登入成功!")
}
func main() {
http.HandleFunc("/login", loginHandler)
fmt.Println("伺服器啟動於 http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
✅ 修補措施
- 使用強密鑰(至少 32 字節,避免使用簡單密鑰)
- 禁止
none
演算法,確保 JWT 使用HS256
或RS256
- 設置 JWT 有效期限,避免長期有效的憑證被竊取後持續使用
3. 憑證重放攻擊(Replay Attack)
如果應用程式沒有設計防止憑證重放機制,攻擊者可以截取合法的登入請求或 JWT,然後在不同的時間或不同的設備上重放這些請求,成功冒充合法用戶。
❌ 攻擊方式
- 攻擊者利用
Burp Suite
攔截合法的 JWT 或 Session,並重放該請求來進行未經授權的操作。
❌ 示範程式碼
package main
import (
"fmt"
"log"
"net/http"
)
func loginHandler(w http.ResponseWriter, r *http.Request) {
authToken := r.Header.Get("Authorization")
if authToken == "valid-token" { // 缺乏唯一性驗證
fmt.Fprintf(w, "登入成功!")
} else {
http.Error(w, "登入失敗", http.StatusUnauthorized)
}
}
func main() {
http.HandleFunc("/login", loginHandler)
fmt.Println("伺服器啟動於 http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
✅ 修補措施
- 為每個請求增加隨機 nonce 值
- 加入時間戳,確保請求過期後無法使用
- 要求每次請求都需重新驗證密鑰
4. 帳號鎖定失敗
如果應用程式未實施帳號鎖定機制,攻擊者可以無限次嘗試登入,利用暴力破解攻擊獲取密碼。
❌ 攻擊方式
- 透過工具(如 Hydra)測試數千種密碼組合,直到成功登入。
❌ 示範程式碼
package main
import (
"fmt"
"log"
"net/http"
)
var failedAttempts = map[string]int{}
func loginHandler(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("username")
password := r.FormValue("password")
if failedAttempts[username] >= 3 {
http.Error(w, "帳號已鎖定,請稍後再試", http.StatusForbidden)
return
}
if username == "admin" && password == "password123" {
failedAttempts[username] = 0
fmt.Fprintf(w, "登入成功!")
} else {
failedAttempts[username]++
http.Error(w, "登入失敗", http.StatusUnauthorized)
}
}
func main() {
http.HandleFunc("/login", loginHandler)
fmt.Println("伺服器啟動於 http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
✅ 修補措施
- 實施帳號鎖定機制(如 5 次錯誤後鎖定 10 分鐘)
- 提供帳號解鎖功能,透過 Email/OTP 來解鎖
- 使用 CAPTCHA 來防止機器人大量測試密碼