Broken Access Control(存取控制失效)發生在系統知道使用者是誰,卻沒有在每一次請求中正確判斷他能否對指定物件執行指定動作。IDOR 與 API 常見的 BOLA 都屬於物件層級授權失效:攻擊者不必破解登入,只要替換路徑、參數、JSON 或檔案中的物件識別碼,就可能讀取、修改或刪除其他帳號與租戶的資料。

先講結論:登入只回答你是誰,授權還要回答你能對哪個物件做什麼
Authentication(身分驗證)確認請求代表哪個使用者、服務或工作階段;Authorization(授權)則根據目前身分、請求動作、目標物件、租戶、所有權、關係與業務狀態,決定這一次操作能否執行。使用者能合法呼叫某個 API,不代表他能操作該 API 接受的每一個物件。
OWASP 將 IDOR 描述為:攻擊者操控 URL 或參數中的識別碼,因為應用程式缺少存取控制檢查,而能存取或修改不應取得的物件。這個物件可能是帳號、文件、工單、交易、發票、裝置、專案、檔案或租戶設定;識別碼則可能是整數、UUID、檔名、Slug、Token 或複合鍵。
修復原則很直接:除公開資源外一律預設拒絕;所有授權決策在可信任的伺服器端執行;每次請求都驗證目前主體是否能對目前物件執行目前動作。前端隱藏按鈕、把 ID 改成 UUID、檢查使用者已登入,或只確認 JWT 中有 user_id,都不等於物件授權。
- 由已驗證的 Session 或 Token 取得目前主體與租戶,不相信 Client 自行提交的 owner_id 或 tenant_id
- 查詢資料時就套用可存取範圍,不先全域取出物件再假設呼叫者有權限
- 對 read、list、create、update、delete、export、approve、share 等每一種動作分別授權
- 使用一致且可重用的 Policy/Middleware/Service 層控制,避免路由各自實作而遺漏
- 修復後以同角色跨帳號、跨租戶、不同動作與批次請求做負向測試
Broken Access Control、IDOR、BOLA、BFLA 與 BOPLA 有什麼差別?
Broken Access Control 是上位類別,涵蓋未登入可存取受保護頁面、一般使用者呼叫管理功能、跨帳號讀取資料、竄改 Token 或強制瀏覽等多種失效。IDOR 是 Web 安全領域長期使用的名稱,聚焦在攻擊者可控制物件參照,而伺服器沒有驗證該物件是否屬於目前允許範圍。
BOLA(Broken Object Level Authorization)是 OWASP API Security Top 10 使用的名稱。它強調 API 端點本身可能是使用者合法可呼叫的,違規發生在傳入不同物件 ID 後,伺服器仍執行了操作。若一般使用者能呼叫只有管理員可用的功能,較接近 BFLA;若使用者能讀寫物件中不應接觸的欄位,則屬物件屬性層級授權失效。
分類的目的不是替報告堆疊縮寫,而是找對控制點。物件層級要驗證『這個物件』;功能層級要驗證『這個操作』;屬性層級要限制『這些欄位』。同一個 API 可能同時存在三種問題,修復時不能只補其中一層。
| 類型 | 核心問題 | 常見示例 | 主要修復控制 |
|---|---|---|---|
| IDOR/BOLA | 目前主體能否操作這一筆物件? | 把 invoice_id 換成其他客戶的值仍能讀取或更新 | 每次請求執行物件層級授權與範圍化查詢 |
| BFLA | 目前角色能否使用這個功能? | 一般成員直接呼叫管理員的停用帳號端點 | 功能/路由層級角色與能力檢查 |
| BOPLA/欄位授權 | 目前主體能否讀寫這個欄位? | 一般使用者提交 role=admin,或 API 回傳內部成本欄位 | 輸入 Allowlist、輸出 DTO 與欄位級 Policy |
| 未驗證存取 | 是否需要登入或有效工作階段? | 未登入可開啟後台頁面或下載私有報表 | 伺服器端驗證、預設拒絕與 Session 管理 |
水平越權、垂直越權與跨租戶越權怎麼判斷?
水平越權發生在權限層級相近的主體之間,例如使用者 A 能讀取使用者 B 的訂單。垂直越權是低權限主體取得高權限能力,例如一般成員批准付款或變更租戶管理員。跨租戶越權則跨越組織、客戶或工作區邊界,常同時包含水平或垂直影響,但因資料隔離承諾與影響範圍,應獨立辨識。
只比較 role 往往抓不到水平與跨租戶風險。兩位使用者都可能是 editor,但 editor A 只能編輯專案 A;同一位 manager 在台灣租戶可批准訂單,不代表能在另一租戶執行相同操作。授權決策必須包含物件與主體之間的關係,而不是只看一個全域角色。
業務狀態也會改變權限。發票在草稿狀態可由建立者修改,送審後只能由財務核准;分享連結可能只允許讀取,不能刪除原始檔。測試與設計權限矩陣時,必須把角色、租戶、關係、動作與狀態放在同一張表裡。
| 越權類型 | 主體與目標關係 | 測試問題 | 主要業務影響 |
|---|---|---|---|
| 水平越權 | 同角色、不同擁有者 | 帳號 A 能否讀寫帳號 B 的物件? | 個資、文件、交易或設定外洩與竄改 |
| 垂直越權 | 低權限對高權限功能或物件 | 一般成員能否執行管理、批准、退款或權限變更? | 權限提升、財務與平台控制失守 |
| 跨租戶越權 | 不同組織或工作區 | 租戶 A 的 Session 能否存取租戶 B 的任何物件或列表? | 客戶資料隔離破壞、合規與契約風險 |
| 狀態型越權 | 同一物件、不同生命週期狀態 | 已鎖定、封存或送審的物件是否仍能被原角色修改? | 工作流程與稽核完整性失效 |
哪些地方都是物件參照?不要只改 URL 裡的流水號
物件 ID 可以出現在 Path、Query String、JSON/XML Body、GraphQL Variable、Header、Cookie、Hidden Field、檔名、下載 Token、WebSocket 訊息與行動 App API。即使畫面沒有顯示 ID,瀏覽器 Network、API Schema、前端狀態或回應中的關聯欄位仍可能暴露可替換的參照。
List、Search、Export、Bulk Update 與 Nested Resource 特別容易漏檢。單筆 GET 已加入權限,但列表查詢未依租戶過濾;主物件有檢查,`/projects/{project}/documents/{document}` 卻沒有確認文件真的屬於該專案;批次陣列只驗證第一筆;匯出工作建立時有權限,下載產物時卻變成公開網址。
測試範圍也要包含間接識別碼,例如 Email、帳號、車輛 VIN、訂單編號、分享 Slug、Storage Key 與報表 Job ID。識別碼是否連號只影響發現難度,不能改變伺服器對每一筆物件做授權的責任。
| 入口 | 物件參照示例 | 常見遺漏 |
|---|---|---|
| URL/Query | /orders/{id}、?account=、?file= | 只保護頁面,API 或下載端點未檢查所有權 |
| Request Body | user_id、tenant_id、projectIds[]、GraphQL variables | 相信 Client 提交的擁有者或批次只驗證部分元素 |
| Header/Cookie | X-Workspace-Id、active_org、impersonate_user | 把可修改的脈絡值直接當授權依據 |
| 檔案與產物 | filename、object key、export job、signed URL | 建立時有權限,下載、預覽或快取時未再次授權 |
| 即時與背景流程 | WebSocket room、queue job、notification target | 訂閱、重連或 Worker 執行時沿用錯誤租戶脈絡 |
為什麼 UUID、雜湊 ID、隱藏欄位與前端限制都不夠?
UUID 或高熵隨機值能降低大量猜測有效 ID 的效率,是合理的縱深措施,但不會讓取得該值的人自動獲得權限。識別碼仍可能從分享連結、瀏覽器歷史、日誌、通知、Referer、另一個 API、客服畫面或資料外洩中被取得;一旦取得,缺少物件授權的端點仍會接受它。
Hidden Field、Disabled Button、前端 Route Guard 與 JavaScript 條件都位於攻擊者可觀察或修改的 Client。它們可以改善操作體驗,不能作為安全邊界。攻擊者可直接建立 HTTP Request、修改 App State,或呼叫未顯示在畫面的 API。
只把 user_id 放進 JWT 再與 Request 中某個 user_id 比對,也只能處理最簡單的所有者模型。真實系統常有團隊共享、代理、審核、服務帳號、資源繼承與跨部門關係,需要明確的 Policy,而不是把 ID 是否相等當成完整授權。
如何安全檢測 IDOR/BOLA?先建立帳號、租戶與物件矩陣
測試前要取得明確授權,使用隔離的測試租戶與可還原資料。至少建立同一租戶的帳號 A、帳號 B,以及另一租戶的帳號 C;依需求加入管理員與唯讀角色。各帳號建立一組可辨識但不含真實資料的文件、工單、訂單或其他物件,記錄它們的 ID、擁有者、租戶、狀態與預期權限。
先用合法流程建立基線,再一次只替換一個物件參照。以帳號 A 的有效 Session 對帳號 B 與租戶 C 的物件執行 read、list、update、delete、export、approve、share 等動作。不能只看 HTTP 200 或 403;還要確認回應是否含資料、資料是否實際改變、背景工作是否建立、通知是否送出,以及 Audit Log 記錄了誰。
遵守最小影響原則:不枚舉真實使用者 ID、不批次下載、不修改不可回復資料,也不使用生產環境其他客戶物件。若意外接觸真實資料,立即停止、保全最小證據並依通報流程處理,不以『確認影響』為由擴大存取。
- 建立 A/B 同角色帳號與 C 跨租戶帳號,各自建立明確所有權的測試物件
- 記錄合法基線的路由、方法、識別碼位置、Session、回應與操作前後狀態
- 逐一替換 Path、Query、Body、Header、檔名與巢狀關聯中的物件參照
- 測試單筆、列表、搜尋、批次、匯出、背景工作與刪除等所有動作
- 確認拒絕發生在資料查詢或業務副作用之前,並檢查 Audit Log 與快取
- 完成後還原測試資料、撤銷 Token,並保留可重現但不含秘密與個資的證據
物件層級授權的正確判斷流程
下圖上方是允許流程:已驗證主體、請求動作、目標物件、租戶與關係一起送進中央 Policy,條件相符後才存取資源。下方則是相同主體嘗試操作其他租戶的物件;即使端點與動作本身合法,只要租戶或關係不符,就應在資料被回傳或修改前拒絕。
這個流程應套用到每一筆物件與每一種動作。List 查詢要限制結果集合,Batch 要逐筆判斷,GraphQL Resolver 要對每個 Node/Edge 執行授權,背景工作也要攜帶足夠且不可被 Client 偽造的主體脈絡。

一筆可信的 IDOR/BOLA 發現需要哪些證據?
報告必須證明『同一個已登入主體,對沒有權限的物件仍成功完成操作』。至少保留帳號角色、租戶、端點、方法、物件 ID 的位置、物件預期擁有者、正常基線、替換後請求、伺服器回應與狀態變化。Session、JWT、API Key 與個資應遮罩,不把可重用秘密放進工單或截圖。
所有權證據不可只靠 ID 外觀推論。應由測試資料建立紀錄、管理畫面、後端測試 Fixture 或經授權的 Audit Log 證明物件確實屬於另一帳號或租戶。對更新、刪除、批准與背景工作,還要記錄操作前後差異與還原結果。
回應差異也值得記錄。404、403 或空集合可能是產品刻意避免物件存在性洩漏的策略;重點是所有未授權情境都不能取得資料或造成副作用。若回應表面失敗但背景 Job 已建立、Cache 已污染或通知已送出,問題仍然存在。
| 證據 | 應記錄內容 | 判讀重點 |
|---|---|---|
| 主體脈絡 | 測試帳號、角色、租戶、Session/Token 類型 | 遮罩秘密值,證明請求代表哪個主體 |
| 物件歸屬 | 物件 ID、擁有者、租戶、關係與狀態 | 以測試 Fixture 或可信後台證明,不靠猜測 |
| 合法基線 | 主體存取自有物件的完整請求與結果 | 確認功能與必要欄位本來可以正常運作 |
| 越權請求 | 只替換目標參照後的 Request、Response 與時間 | 控制變因,證明是物件授權失效 |
| 實際影響 | 讀取內容、更新前後、背景 Job、通知與 Audit Log | 以最小可回復操作證明,停止擴大存取 |
| 修復複驗 | 修復版本、拒絕結果、相鄰端點與合法流程回歸 | 確認所有動作與所有載入路徑一致套用 Policy |
核心修復:把可存取範圍寫進資料查詢,而不是先用 ID 全域查找
最穩定的模式是從目前已驗證主體的可存取集合中查找物件。例如不要以 `findById(request.id)` 全域取得 Project,再相信呼叫者有權限;應使用目前租戶、成員關係或 Policy 產生的 Scope 查詢,讓未授權物件與不存在物件都無法進入後續業務邏輯。
對更新與刪除也要維持相同邊界。可採 `UPDATE ... WHERE id = ? AND tenant_id = ?` 後檢查影響筆數,或先由 Policy 取得受允許的資源再執行交易。避免在授權檢查與實際更新之間留下可被狀態變更利用的時間差,重要動作應在同一交易或具一致性的控制中完成。
授權不應散落在 Controller 的幾個 if。將 Policy 集中到框架 Guard、Service、Repository Scope 或專用授權元件,明確輸入 subject、action、resource 與 context,並採預設拒絕。所有舊版 API、行動版端點、背景 Worker、匯出與管理功能都應重用同一套規則。
| 情境 | 脆弱模式 | 安全方向 |
|---|---|---|
| 讀取單筆 | 全域依 id 查找後直接序列化 | 從目前主體/租戶可見的 Scope 內依 id 查找 |
| 更新/刪除 | 只檢查登入後依 Client id 執行 | Policy 通過後在範圍化條件與交易中修改 |
| 列表/搜尋 | 先取全部資料,再由前端隱藏 | 資料庫查詢即套用租戶、關係、狀態與欄位限制 |
| 巢狀資源 | 只檢查 project id,不確認 document 關係 | 確認父子關係且兩者都在主體可存取範圍 |
| 批次操作 | 只驗證第一筆或外層容器 | 逐筆授權並定義全失敗或部分成功的安全語意 |
RBAC、ABAC 與 ReBAC 該怎麼選?
RBAC 依角色授權,適合表達 admin、editor、viewer 能使用哪些功能,但單靠角色很難描述『editor 只能改自己專案中的草稿』。ABAC 使用主體、物件、動作與環境屬性,例如 department、tenant、classification、status 與時間;ReBAC 則直接表達 owner、member、manager、shared-with 等關係。
多租戶與協作產品通常需要組合:RBAC 決定功能能力,ABAC/ReBAC 限制物件、租戶、關係與狀態。無論採哪種模型,都要有單一可信來源、可測試的 Policy、明確優先順序與預設拒絕,避免同時存在多套互相矛盾的角色旗標。
Policy 的可讀性與營運也很重要。權限變更要能稽核,群組與共享關係要有生命週期,離職、移出租戶或撤銷分享後應立即失效;快取的授權結果要有正確的主體、租戶、版本與失效條件。
| 模型 | 主要判斷依據 | 適合場景 | 需留意的限制 |
|---|---|---|---|
| RBAC | 角色與能力 | 管理功能、部門職責、粗粒度功能控制 | 角色爆炸,難表達個別物件與關係 |
| ABAC | 主體、物件、動作、環境屬性 | 多租戶、資料分級、狀態與條件式授權 | 屬性來源與 Policy 優先順序要一致 |
| ReBAC | 主體與物件之間的關係 | 共享文件、專案成員、組織與階層繼承 | 關係圖更新、繼承與撤銷要可稽核 |
| 組合模式 | 角色能力加物件屬性與關係 | 大多數企業協作與 SaaS 平台 | 必須集中決策,避免各服務自行解讀 |
API、GraphQL 與批次端點為什麼特別容易出現 BOLA?
API 經常由 Client 傳入物件 ID,伺服器又不保存完整畫面狀態,因此每個接收 ID 並對物件執行動作的端點都必須做物件授權。GET 有資料外洩風險,POST、PUT、PATCH、DELETE 則可能建立、竄改或刪除資料;不能只保護寫入方法。
GraphQL 必須在 Resolver 與資料載入層對每個 Node 與 Edge 套用授權。只保護頂層 Query,可能讓 Nested Resolver 載入其他租戶資料;DataLoader、Connection 與 Fragment 也不能繞過欄位與物件 Policy。Introspection 是否開啟不是 BOLA 的根因,關閉它也不能修復缺少授權。
Batch API 要逐筆判斷輸入陣列中的每個 ID,並定義清楚的原子性。若採全部成功或全部失敗,任何未授權項目都應在副作用前停止;若允許部分成功,回應不能洩漏其他物件是否存在,也要確保成功項目確實屬於目前範圍。
- REST 的 Path、Query、Body 與 Header 物件參照都必須進入同一授權流程
- GraphQL 對 Root、Nested Resolver、Node、Edge 與欄位分別驗證,避免 N+1 優化繞過 Policy
- Batch 逐筆授權,明確規定錯誤處理、交易與回應是否揭露物件存在性
- 舊版、行動版、內部與 Partner API 採相同控制,不因未公開文件就視為可信
- API Gateway 可做粗粒度驗證,物件所有權與業務關係仍應由知道資料語意的服務判斷
多租戶系統如何避免跨客戶資料外洩?
租戶脈絡應從已驗證的成員關係、Session 或受信任的服務身分推導,不能只相信 `tenant_id`、`organization_id`、Subdomain 或 X-Workspace-Id。即使 Client 需要選擇工作區,伺服器仍要確認目前主體是該租戶的有效成員,並在每次資料查詢中套用租戶限制。
共享資料庫應把 tenant_id 納入唯一鍵、索引、查詢與關聯約束;資料庫 Row-Level Security 可作為縱深控制,但 Policy、連線角色與繞過權限需要正確設定。每租戶資料庫或 Schema 能增加隔離,仍不能取代應用層對物件與動作的授權。
服務對服務呼叫也要保留原始主體與租戶語意。背景 Worker 不應使用全域服務帳號後依 Client 傳來的 ID 任意處理;事件、Queue Message 與排程任務要包含可驗證的租戶、觸發者與 Policy Version,並在執行時重新確認權限或使用有限範圍能力。
檔案、報表、匯出與 Signed URL 要怎麼授權?
私有檔案不應只靠難猜路徑或放在 Web Root。下載、預覽、縮圖、轉檔與報表端點要先驗證目前主體對來源物件的權限,再由受控服務串流檔案,或發出範圍有限、短效且不可任意改寫目的物件的 Signed URL。
Signed URL 證明持有人取得一段時間內的存取能力,卻不會自動知道目前帳號是否已離職、分享是否撤銷、檔案是否改為機密。高敏感內容可採一次性 Token、短效期限、受眾與動作綁定、下載代理與即時撤銷;URL 不應進入分析、錯誤日誌或第三方 Referer。
非同步匯出有兩個授權時點:建立 Job 時要限制資料範圍,下載產物時也要確認 Job 與檔案屬於目前允許的租戶及主體。只檢查 job_id 是否存在,或把完成檔案放到公開 Bucket,都是常見的 BOLA 路徑。
快取、搜尋索引與即時連線也必須維持授權邊界
應用快取與 CDN 的 Cache Key 若只包含 URL,不含租戶、主體或正確的授權變體,可能把一位使用者的私有回應提供給另一位使用者。私有資料通常應禁止 Shared Cache,或以可靠的 Cache-Control、Vary 與應用層 Key 隔離;授權結果本身也要在角色、關係或租戶變更後失效。
搜尋索引、分析倉儲與向量檢索常是資料的第二條讀取路徑。索引文件必須保留租戶與存取屬性,查詢時在資料來源端過濾,不先取回全部結果再由 Client 隱藏。Snippet、Facet、Count 與 Autocomplete 也可能洩漏未授權資料。
WebSocket、SSE 與 Pub/Sub 要在訂閱 Channel、Room 或 Topic 時驗證權限,重連、Token Refresh 與成員關係變更後重新評估。只在建立 Socket 時登入一次,之後接受任意 room_id,仍是物件層級授權失效。
403 還是 404?拒絕行為、日誌與告警怎麼設計?
未授權物件回 403 或 404 都可能合理。404 能降低未授權呼叫者確認物件是否存在的能力;403 則較能表達已理解但拒絕。產品應依威脅模型訂出一致策略,最重要的是回應內容、時間、長度與副作用不能洩漏敏感資訊或在拒絕前完成操作。
所有存取控制失敗都應留下可關聯的安全日誌,包括時間、主體、租戶、動作、資源類型、遮罩後識別碼、Policy 結果與 Request ID;不要記錄完整 Token、私密欄位或下載 URL。重複跨物件、跨租戶與高權限操作應觸發適當告警與速率限制。
速率限制能降低自動枚舉與大量存取的傷害,但不能修復單次越權。WAF 或 API Gateway 可偵測 ID 大量變動,仍不知道真實所有權與業務關係;最終允許或拒絕必須由可信任的伺服器端授權邏輯決定。
如何把授權負向測試放進 CI?
先把權限模型寫成可執行矩陣:列是主體角色與關係,欄是資源與動作,格子標示 allow 或 deny。每一個 allow 至少有正常測試,每一個 deny 都要有負向測試;對跨租戶、撤銷分享、狀態變更與停用帳號另外建立回歸案例。
API 整合測試可由 Fixture 建立帳號 A、B、C 與各自物件,以 A 的憑證逐一呼叫 B/C 的 read、update、delete、export 等端點,確認沒有資料與副作用。Property-based Test 可自動組合不同主體、物件與動作,尋找 Policy 缺口;新增端點或資源類型時,要求同步更新矩陣。
測試不能只 Mock 授權回傳值。至少一層要從 HTTP/GraphQL 入口跑到真實 Policy 與資料查詢,才能捕捉 Middleware 遺漏、Resolver 繞過、錯誤 Repository Scope 與 Cache 污染。重要 Policy 變更應保留審查與可追蹤版本。
| 測試層 | 主要目的 | 代表性案例 |
|---|---|---|
| Policy Unit Test | 驗證角色、屬性、關係與狀態規則 | owner 可改草稿、viewer 不可改、送審後 owner 不可改 |
| Repository/Scope Test | 確認資料查詢只回傳允許集合 | 租戶 A 查詢永遠不含租戶 B,列表與 Count 一致 |
| API Integration Test | 捕捉路由、Middleware、Resolver 與序列化遺漏 | 以 A 的 Token 對 B 物件執行所有 HTTP 動作 |
| End-to-End Test | 驗證實際登入、分享、撤銷與工作流程 | 分享後可讀、撤銷後立即拒絕且快取失效 |
| Security Regression | 固定曾發生弱點與相鄰根因範圍 | 舊版 API、批次、匯出、檔案與背景工作同步阻擋 |
發現 IDOR/BOLA 後的修復順序
先控制高影響路徑:停止公開下載、停用脆弱端點、限制高風險動作、縮短 Token 或 Signed URL 有效期,並監控是否有大量跨物件存取。若存在真實資料外洩或竄改跡象,依事件應變程序保全日誌、界定時間與租戶範圍,不要先清除證據。
接著修根因而不是只封鎖已知 ID。建立可重用的物件 Policy 與範圍化查詢,盤點同一資源的所有讀寫路徑,包括舊版 API、行動端、管理端、批次、匯出、檔案、快取、搜尋與背景 Worker。補上負向測試與 Audit Log,再進行跨帳號與跨租戶複驗。
最後檢視既有存取紀錄。依資料敏感度、未授權可能性與法規契約義務,由事件應變、法務、隱私與客戶溝通負責人共同決定通知與後續措施。修復完成不等於歷史影響已消失。
- 立即限制高風險讀寫、下載與批次路徑,保留證據並啟動監控
- 確認受影響資源、動作、角色、租戶、版本與所有平行端點
- 以中央 Policy、預設拒絕與範圍化查詢修復共同根因
- 加入跨帳號、跨租戶、狀態、批次、檔案與快取的負向測試
- 複驗合法流程、未授權流程、日誌、告警與撤銷是否一致生效
- 依事件與法規流程評估歷史存取、客戶影響與通知責任
修復後怎麼複驗,才不是只把 PoC 擋掉?
先重跑原始越權請求,確認未授權資料不再回傳且狀態完全沒有改變;再以相同物件測試 read、update、delete、export、share、approve 等相鄰動作。對同資源的列表、搜尋、巢狀路由、GraphQL、舊版 API、批次與下載端點做根因範圍回歸。
接著驗證權限生命週期:加入成員後可存取、移除後立即失效;分享後只有指定能力、撤銷後 Cache 與 Signed URL 不再提供資料;租戶切換不會沿用前一租戶內容;物件狀態改變後 Policy 重新評估。
最後確認合法使用者仍能完成工作,而且拒絕結果不洩漏物件存在性。報告應記錄修復版本、Policy 變更、測試帳號矩陣、所有通過與拒絕案例,以及尚未覆蓋的第三方整合或非同步流程。
| 複驗面向 | 應通過的結果 | 常見殘留風險 |
|---|---|---|
| 原始 PoC | 跨帳號/租戶請求在副作用前拒絕 | 只封鎖特定 ID 或只改回應碼 |
| 相鄰動作 | 同資源所有讀寫、匯出與業務動作一致授權 | GET 已修,PATCH、DELETE 或 Export 遺漏 |
| 平行入口 | Web、API、GraphQL、Mobile、Worker 與檔案共用 Policy | 舊版或內部端點仍可繞過 |
| 生命週期 | 角色/關係撤銷後 Session、Cache、索引與 URL 立即失效 | 權限快取或長效 Signed URL 延遲撤銷 |
| 合法流程 | 授權使用者與整合仍能正常完成操作 | 過度修復造成業務中斷或錯誤拒絕 |
給產品、開發與資安團隊的實務檢查表
物件授權不是上線前做一次的檢查,而是每新增資源、路由、角色、分享關係、匯出流程與整合時都要維護的系統能力。最有效的做法,是讓權限模型、程式控制、測試矩陣、日誌與弱點掃描使用同一套資源與動作語言。
- 所有非公開資源預設拒絕,授權只在可信任的伺服器端執行
- Session/Token 決定主體,伺服器驗證租戶與關係,不相信 Client 的擁有者欄位
- 每個接收物件參照的端點與每種動作都執行物件層級授權
- 單筆、列表、搜尋、GraphQL、批次、檔案、匯出、快取與背景工作使用一致 Policy
- UUID、Signed URL、WAF 與速率限制只作縱深控制,不代替授權
- CI 以 A/B/跨租戶帳號持續執行允許與拒絕案例
- 日誌可追蹤主體、租戶、資源、動作與 Policy 結果,但不記錄秘密或個資
- 修復以根因範圍複驗,不只重跑單一 URL 或單一識別碼


