在設計系統時,我們往往專注於正常運作時的邏輯,但當系統遇到非預期的錯誤或故障時,其處理方式同樣至關重要。「故障時的安全性 (Fail-Safe)」是一個核心的安全設計原則,它要求系統在發生故障時,必須進入並保持在一個安全的狀態,而不是一個充滿風險的未知狀態。
什麼是「故障時的安全性」?
這個原則指的是,當一個安全控制機制(如身份驗證、權限檢查、加密驗證)因任何原因執行失敗時,系統的預設行為應該是拒絕操作,而不是允許操作繼續。
如果錯誤處理不當,允許使用者在安全檢查失敗後仍能繼續存取資源,那麼這個錯誤處理本身就構成了一個嚴重的安全漏洞。
攻擊案例分析
案例一:繞過雙重認證 (2FA)
- 正常流程:使用者登入時,需先輸入密碼,然後輸入手機上的一次性權杖 (OTP)。兩者皆正確才能登入。
- 攻擊情境:攻擊者已透過釣魚等方式竊取到使用者的密碼。他輸入正確的密碼,進入了第二步 OTP 驗證。
- 觸發故障:攻擊者沒有 OTP,於是他隨便輸入一個錯誤的權杖。
- 不安全的故障處理:後端系統在驗證 OTP 時,可能因為網路問題或內部程式碼錯誤,拋出了一個未被妥善處理的異常 (Exception)。這個異常中斷了正常的「驗證失敗」流程。
- 攻擊成功:由於驗證流程被意外中斷,系統沒有明確地拒絕存取,攻擊者此時直接嘗試訪問登入後的個人資料頁面 URL,竟然成功了。安全控制在故障時,錯誤地「放行」了未完成驗證的請求。
案例二:TLS 驗證失敗導致降級攻擊
- 正常流程:手機 App 透過 HTTPS 連線到銀行伺服器,並使用 SSL Pinning 技術驗證伺服器憑證的真實性,防止中間人攻擊。
- 攻擊情境:攻擊者在公共 Wi-Fi 下發動中間人攻擊,攔截了 App 的網路流量,並提供一個偽造的伺服器憑證。
- 觸發故障:App 的 SSL Pinning 機制檢測到憑證不符,驗證失敗。
- 不安全的故障處理:App 在處理這個驗證失敗的錯誤時,沒有直接中斷連線並警告使用者,而是錯誤地決定「降級」為使用不加密的 HTTP 協定繼續通訊。
- 攻擊成功:一旦降級為 HTTP,攻擊者便可以完全控制、竊聽和竄改 App 與伺服器之間的所有通訊內容。
風險與影響
- 繞過安全控制:攻擊者可以繞過身份驗證、權限檢查等核心安全機制。
- 權限提升:在認證或授權失敗時,使用者可能意外獲得比預期更高的權限。
- 敏感資料洩漏:導致資料外洩、品牌聲譽受損及相關的財務後果。
防禦與預防措施
預設拒絕 (Default Deny)
這是最重要的原則。除非使用者被明確地授予權限,否則所有存取都應被拒絕。在程式碼中,這意味著你的 if/else
或 try/catch
結構,其預設或最終的 else
/catch
區塊應該是拒絕存取。
結構化的錯誤處理
開發者應在設計階段就識別出所有可能發生故障的區域,並為每個操作定義明確的結果。
一個安全的程式碼區塊,只應有三種可能的確定性結果:
- 授權成功 -> 執行操作。
- 授權失敗 -> 拒絕操作,不執行。
- 發生異常 -> 立即回滾 (Rollback) 任何已執行的部分操作,拒絕存取,並向使用者顯示通用的錯誤訊息(避免洩漏過多內部細節)。
說些什麼吧!