API 安全測試方法與工具

API Security Testing Methods and Tools

API 安全測試概述

API(Application Programming Interface)已成為現代應用程式架構的核心組件。隨著微服務架構和雲端服務的普及,API 的數量急劇增加,這也使得 API 安全測試變得更加重要。

為什麼 API 安全測試很重要?

  • 資料外洩風險:API 直接暴露後端資料,若未妥善保護,可能導致敏感資料外洩
  • 業務邏輯漏洞:API 端點可能存在業務邏輯缺陷,允許未授權的操作
  • 攻擊面擴大:每個 API 端點都是潛在的攻擊入口
  • 合規要求:GDPR、PCI-DSS 等法規要求對 API 進行安全評估

API 安全測試類型

測試類型說明測試重點
功能測試驗證 API 是否按預期工作請求/回應格式、錯誤處理
安全測試識別安全漏洞認證、授權、輸入驗證
滲透測試模擬攻擊者行為漏洞利用、權限提升
模糊測試發送異常輸入邊界條件、異常處理

常見 API 漏洞

根據 OWASP API Security Top 10,以下是最常見的 API 安全漏洞:

1. Broken Object Level Authorization (BOLA)

物件層級授權失效是最常見的 API 漏洞。攻擊者透過修改請求中的物件 ID 來存取其他使用者的資料。

1
2
3
4
5
6
7
# 原始請求 - 存取自己的訂單
GET /api/orders/1001 HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# 攻擊請求 - 嘗試存取其他用戶的訂單
GET /api/orders/1002 HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

2. Broken Authentication

認證機制缺陷可能導致帳號接管或未授權存取。

常見問題:

  • 弱密碼政策
  • 缺少帳號鎖定機制
  • Token 未正確失效
  • 憑證在 URL 中傳輸

3. Excessive Data Exposure

API 回傳過多資料,依賴前端進行過濾。

1
2
3
4
5
6
7
8
9
// 不安全的回應 - 包含敏感資訊
{
  "user_id": 123,
  "username": "john",
  "email": "john@example.com",
  "password_hash": "$2b$12$...",
  "credit_card": "4111-1111-1111-1111",
  "ssn": "123-45-6789"
}

4. Lack of Resources & Rate Limiting

缺少速率限制可能導致 DoS 攻擊或暴力破解。

5. Broken Function Level Authorization

功能層級授權失效允許攻擊者存取管理功能。

1
2
3
# 一般使用者嘗試存取管理 API
DELETE /api/admin/users/456 HTTP/1.1
Authorization: Bearer <user_token>

認證與授權測試

JWT Token 測試

JWT(JSON Web Token)是 API 認證的常見方式。測試重點包括:

1. 簽名驗證測試

1
2
3
4
5
6
7
8
9
# 原始 JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.signature

# 測試 1:移除簽名(alg: none 攻擊)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyX2lkIjoxMjN9.

# 測試 2:修改 payload 中的角色
# Header: {"alg":"HS256","typ":"JWT"}
# Payload: {"user_id":123,"role":"admin"}

2. Token 過期測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import jwt
import time

# 產生過期的 Token
expired_token = jwt.encode(
    {"user_id": 123, "exp": int(time.time()) - 3600},
    "secret_key",
    algorithm="HS256"
)

# 測試 API 是否接受過期 Token

OAuth 2.0 測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 測試重定向 URI 驗證
GET /oauth/authorize?
    client_id=legit_client&
    redirect_uri=https://evil.com/callback&
    response_type=code&
    scope=read HTTP/1.1

# 測試 CSRF 保護(缺少 state 參數)
GET /oauth/authorize?
    client_id=legit_client&
    redirect_uri=https://app.com/callback&
    response_type=code HTTP/1.1

授權測試清單

  • 水平權限提升:存取其他同級使用者的資源
  • 垂直權限提升:存取更高權限的功能
  • 角色切換:在不同角色間切換時的權限檢查
  • Token 替換:使用其他使用者的 Token

輸入驗證測試

SQL Injection 測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 測試 SQL 注入
GET /api/users?id=1' OR '1'='1 HTTP/1.1

# JSON 格式的 SQL 注入
POST /api/search HTTP/1.1
Content-Type: application/json

{
  "query": "'; DROP TABLE users; --"
}

NoSQL Injection 測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# MongoDB 注入測試
POST /api/login HTTP/1.1
Content-Type: application/json

{
  "username": {"$gt": ""},
  "password": {"$gt": ""}
}

# 運算子注入
{
  "username": "admin",
  "password": {"$regex": ".*"}
}

XML External Entity (XXE) 測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
POST /api/upload HTTP/1.1
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
  <data>&xxe;</data>
</root>

Server-Side Request Forgery (SSRF) 測試

1
2
3
4
5
6
POST /api/fetch-url HTTP/1.1
Content-Type: application/json

{
  "url": "http://169.254.169.254/latest/meta-data/"
}

速率限制測試

測試方法

1
2
3
4
5
6
7
# 使用 curl 進行速率限制測試
for i in {1..100}; do
  curl -s -o /dev/null -w "%{http_code}\n" \
    -X POST https://api.example.com/login \
    -H "Content-Type: application/json" \
    -d '{"username":"test","password":"test123"}'
done | sort | uniq -c

繞過技巧測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 測試 X-Forwarded-For 繞過
POST /api/login HTTP/1.1
X-Forwarded-For: 1.2.3.4
X-Real-IP: 5.6.7.8

# 測試大小寫變化
POST /api/Login HTTP/1.1
POST /API/login HTTP/1.1

# 測試路徑變化
POST /api/login/ HTTP/1.1
POST /api/./login HTTP/1.1

Postman 安全測試

環境設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 在 Pre-request Script 中設定認證
pm.environment.set("auth_token", pm.environment.get("jwt_token"));

// 動態產生 timestamp 和簽名
const timestamp = Date.now();
const signature = CryptoJS.HmacSHA256(
    timestamp + pm.environment.get("api_key"),
    pm.environment.get("secret")
).toString();

pm.environment.set("timestamp", timestamp);
pm.environment.set("signature", signature);

自動化測試腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Tests 標籤頁的測試腳本
pm.test("狀態碼應為 200", function() {
    pm.response.to.have.status(200);
});

pm.test("回應時間應小於 500ms", function() {
    pm.expect(pm.response.responseTime).to.be.below(500);
});

pm.test("不應包含敏感資訊", function() {
    const response = pm.response.json();
    pm.expect(response).to.not.have.property("password");
    pm.expect(response).to.not.have.property("password_hash");
    pm.expect(response).to.not.have.property("credit_card");
});

pm.test("應有適當的安全標頭", function() {
    pm.response.to.have.header("X-Content-Type-Options");
    pm.response.to.have.header("X-Frame-Options");
});

Collection Runner 批次測試

  1. 建立包含各種測試案例的 Collection
  2. 使用 Data File(CSV/JSON)提供測試資料
  3. 執行 Collection Runner 進行批次測試

Burp Suite API 測試

設定 API 測試

  1. 匯入 OpenAPI/Swagger 規格

    • 前往 Target > Site map
    • 右鍵選擇 Import OpenAPI definition
    • 選擇 swagger.json 或 openapi.yaml 檔案
  2. 設定認證

    • Project options > Sessions 中設定 Session handling rules
    • 新增 Macro 自動取得和更新 Token

使用 Repeater 測試 API

1
2
3
4
5
6
7
# 測試 BOLA 漏洞
GET /api/v1/users/{{user_id}}/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer {{token}}

# 逐一測試不同的 user_id 值
# user_id: 1, 2, 3, ..., 100

Intruder 自動化測試

設定 Payload 位置:

1
2
3
GET /api/orders/§1001§ HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Payload 類型設定:

  • Numbers: 1000-2000, step 1
  • Simple list: 常見的 ID 值
  • Brute forcer: 字元組合

自動化工具(OWASP ZAP)

安裝與設定

1
2
3
4
5
6
# Docker 安裝
docker pull ghcr.io/zaproxy/zaproxy:stable

# 執行 ZAP
docker run -u zap -p 8080:8080 -p 8090:8090 \
  ghcr.io/zaproxy/zaproxy:stable zap-webswing.sh

API 掃描

1
2
3
4
5
6
# 使用 ZAP API 掃描
docker run --rm -v $(pwd):/zap/wrk:rw \
  ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \
  -t https://api.example.com/openapi.json \
  -f openapi \
  -r api-scan-report.html

ZAP 自動化腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from zapv2 import ZAPv2

# 連接 ZAP
zap = ZAPv2(apikey='your-api-key', proxies={
    'http': 'http://127.0.0.1:8080',
    'https': 'http://127.0.0.1:8080'
})

# 匯入 OpenAPI 定義
zap.openapi.import_url('https://api.example.com/openapi.json')

# 執行主動掃描
scan_id = zap.ascan.scan('https://api.example.com')

# 等待掃描完成
while int(zap.ascan.status(scan_id)) < 100:
    print(f'掃描進度: {zap.ascan.status(scan_id)}%')
    time.sleep(5)

# 取得掃描結果
alerts = zap.core.alerts()
for alert in alerts:
    print(f"漏洞: {alert['name']} - 風險: {alert['risk']}")

測試清單

認證測試清單

  • 測試預設憑證
  • 測試弱密碼
  • 測試暴力破解防護
  • 測試帳號列舉
  • 測試密碼重設流程
  • 測試 Session 管理
  • 測試 Token 安全性

授權測試清單

  • 測試 BOLA(物件層級授權)
  • 測試 BFLA(功能層級授權)
  • 測試水平權限提升
  • 測試垂直權限提升
  • 測試 CORS 設定

輸入驗證測試清單

  • SQL Injection
  • NoSQL Injection
  • Command Injection
  • XSS(跨站腳本)
  • XXE(XML 外部實體)
  • SSRF(伺服器端請求偽造)
  • Path Traversal

資料保護測試清單

  • 敏感資料是否加密傳輸
  • API 回應是否包含過多資訊
  • 錯誤訊息是否洩漏敏感資訊
  • 日誌是否記錄敏感資料

速率限制測試清單

  • 登入端點是否有速率限制
  • 密碼重設是否有速率限制
  • 一般 API 是否有速率限制
  • 速率限制是否可被繞過

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy