OWASP Top 10 - 不安全的設計模式

OWASP Top 10 - Insecure Design

不安全設計概述

不安全設計(Insecure Design)是 OWASP Top 10 2021 年版本中新增的類別,位列第四名。這個類別聚焦於與設計和架構缺陷相關的風險,強調在開發之前就需要進行安全設計和威脅建模的重要性。

不安全設計指的是在系統設計階段就存在的根本性安全缺陷,這些缺陷無法透過完美的實作來修復。即使程式碼撰寫得毫無瑕疵,如果設計本身就有問題,系統仍然會存在安全風險。

不安全設計的特徵:

  • 缺乏安全需求的定義
  • 未進行威脅建模分析
  • 忽略安全設計原則
  • 缺少業務邏輯驗證
  • 未考慮濫用場景(Abuse Cases)

設計缺陷 vs 實作缺陷

理解設計缺陷和實作缺陷的區別對於建立安全系統至關重要。

設計缺陷(Design Flaws)

設計缺陷是在系統架構和設計階段產生的問題,通常需要重新設計才能修復。

範例:

1
2
3
4
5
6
7
問題:密碼重設功能透過安全問題驗證身份
設計:使用者可以設定「您的寵物名字是什麼?」作為安全問題

缺陷分析:
- 安全問題的答案通常可以從社群媒體找到
- 答案的變化有限,容易被暴力破解
- 這是設計層面的問題,無法透過更好的實作來修復

實作缺陷(Implementation Bugs)

實作缺陷是在程式碼層面產生的問題,可以透過修改程式碼來修復。

範例:

1
2
3
4
5
6
# 實作缺陷:SQL 注入
query = "SELECT * FROM users WHERE id = " + user_input

# 修復後的實作
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_input,))

兩者的關係

類型發生階段修復方式成本
設計缺陷架構設計重新設計
實作缺陷程式開發修改程式碼中低

常見不安全設計模式

1. 缺乏速率限制

許多系統未對敏感操作實施速率限制,導致暴力破解攻擊變得可行。

不安全設計:

1
2
3
4
登入功能:
- 無登入嘗試次數限制
- 無帳號鎖定機制
- 無驗證碼機制

安全設計:

1
2
3
4
登入功能:
- 5 次失敗後啟用驗證碼
- 10 次失敗後暫時鎖定帳號 15 分鐘
- 記錄異常登入行為並發送警報

2. 不安全的密碼重設流程

不安全設計範例:

1
2
3
4
5
步驟 1:輸入電子郵件
步驟 2:回答安全問題
步驟 3:設定新密碼

問題:安全問題答案容易被猜測或透過社交工程取得

安全設計範例:

1
2
3
4
步驟 1:輸入電子郵件
步驟 2:發送一次性驗證連結到電子郵件
步驟 3:連結有效期 15 分鐘,使用後立即失效
步驟 4:設定新密碼(需符合密碼政策)

3. 信任用戶端輸入

不安全設計:

1
2
3
// 前端計算價格
const totalPrice = quantity * unitPrice * (1 - discount);
// 直接將計算結果發送到後端

安全設計:

1
2
3
4
5
6
# 後端驗證所有計算
def calculate_order_total(order_id, quantity):
    product = get_product(order_id)
    discount = get_user_discount(current_user)
    # 所有價格計算都在後端完成
    return quantity * product.price * (1 - discount)

4. 缺乏業務流程驗證

不安全設計:

1
2
3
4
5
購物流程:
1. 加入購物車 → 2. 結帳 → 3. 付款

問題:系統未驗證用戶是否已完成前一步驟
攻擊:直接跳到步驟 3 可能繞過某些檢查

安全設計:

1
2
3
4
5
購物流程(含狀態驗證):
1. 加入購物車 [狀態: CART_READY]
2. 結帳 [需要狀態: CART_READY → CHECKOUT]
3. 付款 [需要狀態: CHECKOUT → PAYMENT]
4. 完成 [需要狀態: PAYMENT → COMPLETED]

5. 過度依賴隱藏欄位

不安全設計:

1
2
3
4
5
<form action="/update-profile">
    <input type="hidden" name="user_id" value="12345">
    <input type="hidden" name="role" value="user">
    <input type="text" name="email" value="user@example.com">
</form>

攻擊者可以修改隱藏欄位的值來提升權限或存取其他用戶資料。

威脅建模

威脅建模是在設計階段識別和評估潛在威脅的系統性方法。

STRIDE 威脅模型

STRIDE 是微軟開發的威脅分類框架:

威脅類型說明對應安全屬性
Spoofing身份偽造身份驗證
Tampering資料竄改完整性
Repudiation否認行為不可否認性
Information Disclosure資訊洩漏機密性
Denial of Service阻斷服務可用性
Elevation of Privilege權限提升授權

威脅建模步驟

步驟 1:定義系統範圍

1
2
3
系統:電子商務平台
元件:Web 前端、API 伺服器、資料庫、付款閘道
資料流:用戶資料、訂單資訊、付款資料

步驟 2:建立資料流程圖(DFD)

1
2
3
4
5
[用戶] ---(HTTPS)---> [Web 應用程式]
                            |
                      [API 伺服器]
                       /        \
              [資料庫]          [付款閘道]

步驟 3:識別威脅

針對每個元件和資料流應用 STRIDE:

1
2
3
4
資料流:用戶 → Web 應用程式
- Spoofing:攻擊者偽造用戶身份
- Tampering:中間人攻擊修改請求
- Information Disclosure:資料傳輸未加密

步驟 4:評估風險

使用風險評估矩陣:

1
2
3
4
風險 = 可能性 × 影響
高風險:需要立即處理
中風險:應在下一版本修復
低風險:可接受或長期計畫修復

安全設計原則

1. 最小權限原則(Principle of Least Privilege)

系統元件只應擁有完成其功能所需的最小權限。

1
2
3
4
5
6
7
8
# Kubernetes Pod 安全設定範例
securityContext:
  runAsNonRoot: true
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL

2. 縱深防禦(Defense in Depth)

多層安全控制,即使一層被突破,其他層仍能提供保護。

1
2
3
4
5
層次架構:
1. 網路層:防火牆、WAF
2. 應用層:輸入驗證、輸出編碼
3. 資料層:加密、存取控制
4. 監控層:日誌記錄、異常偵測

3. 預設安全(Secure by Default)

系統預設配置應該是最安全的狀態。

1
2
3
4
5
6
7
# 不安全:預設允許所有
DEBUG = True
ALLOWED_HOSTS = ['*']

# 安全:預設限制
DEBUG = False
ALLOWED_HOSTS = ['www.example.com']

4. 失敗安全(Fail Secure)

當系統發生錯誤時,應該預設拒絕存取而非開放存取。

1
2
3
4
5
6
7
def check_permission(user, resource):
    try:
        return permission_service.check(user, resource)
    except Exception as e:
        logging.error(f"Permission check failed: {e}")
        # 失敗時預設拒絕存取
        return False

5. 信任邊界(Trust Boundaries)

明確定義系統中的信任邊界,跨越邊界的資料必須經過驗證。

1
2
3
[不信任區域]          [信任邊界]          [信任區域]
   用戶輸入    --->   驗證/清理    --->   內部處理
   外部 API   --->   驗證/清理    --->   業務邏輯

案例分析

案例 1:電影票預訂系統漏洞

情境:

某電影院的線上訂票系統允許用戶預訂特定場次的座位。

不安全設計:

1
2
3
4
5
6
7
流程設計:
1. 用戶選擇場次和座位
2. 系統保留座位 10 分鐘
3. 用戶完成付款
4. 座位確認

問題:系統未限制單一用戶可以預訂的座位數量

攻擊場景:

攻擊者可以自動化預訂所有座位,造成其他用戶無法購票,然後在時間到期前取消預訂,反覆進行造成服務中斷。

安全設計修正:

1
2
3
4
5
改進措施:
1. 限制每位用戶每個場次最多預訂 6 個座位
2. 同一 IP 每分鐘最多 10 次預訂請求
3. 預訂時需要完成驗證碼
4. 多次取消預訂將觸發帳號審查

案例 2:銀行轉帳安全問題

情境:

某銀行的網路銀行允許用戶進行轉帳操作。

不安全設計:

1
2
3
4
5
6
# 轉帳 API
def transfer(from_account, to_account, amount):
    if get_balance(from_account) >= amount:
        debit(from_account, amount)
        credit(to_account, amount)
        return {"status": "success"}

問題分析:

  • 未驗證用戶是否擁有 from_account
  • 可能存在競態條件(Race Condition)
  • 缺乏交易記錄和審計日誌

安全設計修正:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@transaction.atomic
def transfer(user, to_account, amount):
    # 驗證用戶權限
    from_account = user.get_primary_account()

    # 使用資料庫鎖防止競態條件
    account = Account.objects.select_for_update().get(id=from_account.id)

    if account.balance < amount:
        raise InsufficientFundsError()

    # 大額轉帳需要額外驗證
    if amount > 50000:
        require_two_factor_auth(user)

    # 執行轉帳並記錄
    TransactionLog.create(
        from_account=from_account,
        to_account=to_account,
        amount=amount,
        user=user,
        ip_address=get_client_ip()
    )

    account.balance -= amount
    account.save()
    credit(to_account, amount)

安全需求整合

安全需求收集

在專案初期就應該收集安全需求,與功能需求同等重要。

安全需求範本:

1
2
3
4
5
6
7
8
需求編號:SEC-001
類別:身份驗證
描述:系統必須支援多因素驗證(MFA)
優先級:高
驗收標準:
- 支援 TOTP 驗證器應用程式
- 支援 SMS 驗證碼
- 高風險操作強制要求 MFA

安全需求類別

類別範例需求
身份驗證密碼複雜度、MFA、Session 管理
授權角色權限、存取控制清單
資料保護加密傳輸、靜態加密、資料遮罩
日誌審計操作記錄、異常偵測、合規報告
可用性速率限制、防 DDoS、故障轉移

將安全納入 SDLC

1
2
3
4
5
6
需求階段 → 安全需求分析、濫用案例定義
設計階段 → 威脅建模、安全架構審查
開發階段 → 安全程式碼審查、SAST
測試階段 → 滲透測試、DAST、安全驗收測試
部署階段 → 安全配置審查、弱點掃描
維運階段 → 持續監控、事件回應、更新管理

測試方法

設計審查

安全架構審查清單:

  • 是否進行威脅建模?
  • 信任邊界是否明確定義?
  • 是否遵循最小權限原則?
  • 敏感資料如何保護?
  • 錯誤處理是否安全?
  • 是否有適當的日誌記錄?

濫用案例測試

針對每個功能設計濫用案例:

1
2
3
4
5
6
7
8
功能:用戶註冊
正常案例:用戶填寫表單,收到驗證信,完成註冊

濫用案例:
1. 攻擊者批量註冊帳號
2. 攻擊者使用他人電子郵件註冊
3. 攻擊者繞過電子郵件驗證
4. 攻擊者利用註冊功能發送垃圾郵件

業務邏輯測試

1
2
3
4
5
6
7
測試項目:訂單流程
測試案例:
1. 跳過付款步驟直接完成訂單
2. 修改訂單金額為負數
3. 使用已使用的優惠券
4. 在庫存為 0 時下單
5. 訂單完成後修改訂單內容

自動化安全測試

1
2
3
4
5
# 使用 OWASP ZAP 進行自動化掃描
zap-cli quick-scan --self-contained --start-options '-config api.disablekey=true' http://target.com

# 使用 Nuclei 進行漏洞掃描
nuclei -u http://target.com -t cves/ -t vulnerabilities/

防護措施

開發階段

  1. 安全培訓:確保開發團隊了解常見安全風險
  2. 威脅建模:在設計階段識別潛在威脅
  3. 安全需求:將安全需求納入開發計畫
  4. 程式碼審查:進行安全導向的程式碼審查

設計階段

  1. 採用安全設計模式:使用經過驗證的安全架構
  2. 實施防禦性設計:假設所有輸入都不可信任
  3. 限制功能暴露:只暴露必要的功能和資料
  4. 設計監控機制:內建安全監控和警報功能

實作建議

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 業務邏輯驗證範例
class OrderService:
    def create_order(self, user, items, discount_code=None):
        # 驗證用戶狀態
        if not user.is_active:
            raise UserInactiveError()

        # 驗證商品庫存
        for item in items:
            if not self.check_inventory(item):
                raise OutOfStockError(item)

        # 驗證折扣碼
        discount = 0
        if discount_code:
            discount = self.validate_discount(discount_code, user)

        # 在後端計算總價
        total = self.calculate_total(items, discount)

        # 建立訂單並記錄
        order = Order.create(
            user=user,
            items=items,
            total=total,
            created_at=datetime.now()
        )

        AuditLog.log(
            action='ORDER_CREATED',
            user=user,
            details={'order_id': order.id, 'total': total}
        )

        return order

參考資料

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