跳至主要内容

A01: 權限控制失效(Broken Access Control)

以下展示兩個不同類型的 A01 權限控制失效(Broken Access Control) 漏洞示例,包括 目錄遍歷(Directory Traversal)功能級存取控制(Function-Level Access Control)


案例 1:目錄遍歷漏洞(Directory Traversal)

  1. 漏洞類型
    • 攻擊者可以存取不應該存取的檔案,例如系統設定檔或其他使用者的私密資料。
  2. 攻擊手法
    • 透過 ../ 或 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 💀


✅ 修補漏洞

修正方式

  1. 限制檔案存取範圍,避免 ../ 跳脫到 uploads/ 目錄外。
  2. 使用 白名單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)

  1. 漏洞類型
    • 攻擊者可以存取管理員 API,即使他們不是管理員。
  2. 攻擊手法
    • 透過直接呼叫 /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!" }

成功繞過權限檢查!即使不是管理員,也能訪問管理後台! 💀


✅ 修補漏洞

修正方式

  1. 正確檢查使用者角色
  2. 使用 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)可以訪問 /adminalice 會收到 403 Forbidden


修補後的安全性提升

案例漏洞攻擊手法修補方式
案例 1目錄遍歷(Directory Traversal)使用 ../ 讀取系統檔案使用 filepath.Clean() 限制目錄存取
案例 2功能級存取控制(Function-Level Access Control)普通使用者直接請求 /admin檢查 role 欄位,確保權限正確