A01: 權限控制失效(Broken Access Control)
以下展示兩個不同類型的 A01 權限控制失效(Broken Access Control) 漏洞示例,包括 目錄遍歷(Directory Traversal) 和 功能級存取控制(Function-Level Access Control)。
案例 1:目錄遍歷漏洞(Directory Traversal)
- 漏洞類型:
- 攻擊者可以存取不應該存取的檔案,例如系統設定檔或其他使用者的私密資料。
- 攻擊手法:
- 透過
../
或 URL 編碼繞過存取限制,讀取敏感檔案。
- 透過
❌ 有漏洞的程式碼
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
// 存取檔案的 API
func fileHandler(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
// **漏洞:沒有檢查非法路徑**
data, err := ioutil.ReadFile("uploads/" + filename)
if err != nil {
http.Error(w, "File not found", http.StatusNotFound)
return
}
w.Write(data)
}
func main() {
http.HandleFunc("/read", fileHandler)
fmt.Println("Server running on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
🔍 測試漏洞
使用 Burp Suite 或手動測試:
GET /read?file=../../etc/passwd HTTP/1.1
Host: localhost:8080
結果:攻擊者成功讀取 etc/passwd
! 💀
✅ 修補漏洞
修正方式
- 限制檔案存取範圍,避免
../
跳脫到uploads/
目錄外。 - 使用 白名單 或
filepath.Clean()
確保檔案路徑合法。
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"path/filepath"
"strings"
)
func secureFileHandler(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
// **修正:限制存取的目錄**
cleanPath := filepath.Clean("uploads/" + filename)
// 確保請求的檔案仍在 "uploads" 內
if !strings.HasPrefix(cleanPath, "uploads/") {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
data, err := ioutil.ReadFile(cleanPath)
if err != nil {
http.Error(w, "File not found", http.StatusNotFound)
return
}
w.Write(data)
}
func main() {
http.HandleFunc("/read", secureFileHandler)
fmt.Println("Server running on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
✅ 修復成功! 現在無法使用 ../
跳脫到 uploads
目錄外。
案例 2:功能級存取控制失效(Function-Level Access Control)
- 漏洞類型:
- 攻擊者可以存取管理員 API,即使他們不是管理員。
- 攻擊手法:
- 透過直接呼叫
/admin
API,繞過前端 UI 限制。
- 透過直接呼叫
❌ 有漏洞的程式碼
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
// 簡單的用戶資料
var users = map[string]string{
"alice": "user",
"bob": "admin",
}
// **漏洞:只檢查是否登入,沒檢查角色**
func adminDashboard(w http.ResponseWriter, r *http.Request) {
username := r.Header.Get("X-User")
if username == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// **這裡沒有檢查角色,所有登入用戶都能存取!**
response := map[string]string{"message": "Welcome to the admin dashboard!"}
json.NewEncoder(w).Encode(response)
}
func main() {
http.HandleFunc("/admin", adminDashboard)
fmt.Println("Server running on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
🔍 測試漏洞
普通使用者存取管理 API
GET /admin HTTP/1.1
Host: localhost:8080
X-User: alice
結果
{ "message": "Welcome to the admin dashboard!" }
成功繞過權限檢查! 即使不是管理員,也能訪問管理後台! 💀
✅ 修補漏洞
修正方式
- 正確檢查使用者角色
- 使用 Middleware 限制權限
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
// 用戶與角色
var users = map[string]string{
"alice": "user",
"bob": "admin",
}
// **安全的權限檢查中介層**
func adminMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username := r.Header.Get("X-User")
role, exists := users[username]
if !exists || role != "admin" {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
// **修正後的管理 API**
func adminDashboard(w http.ResponseWriter, r *http.Request) {
response := map[string]string{"message": "Welcome to the admin dashboard!"}
json.NewEncoder(w).Encode(response)
}
func main() {
mux := http.NewServeMux()
mux.Handle("/admin", adminMiddleware(http.HandlerFunc(adminDashboard)))
fmt.Println("Server running on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
✅ 修復成功! 現在只有 bob
(admin)可以訪問 /admin
,alice
會收到 403 Forbidden
。
修補後的安全性提升
案例 | 漏洞 | 攻擊手法 | 修補方式 |
---|---|---|---|
案例 1 | 目錄遍歷(Directory Traversal) | 使用 ../ 讀取系統檔案 | 使用 filepath.Clean() 限制目錄存取 |
案例 2 | 功能級存取控制(Function-Level Access Control) | 普通使用者直接請求 /admin | 檢查 role 欄位,確保權限正確 |