本卡屬 FR-114 資安修正(母卡 CM-2019),第 2 批「只驗登入、不檢查歸屬」卡 2-9(接續卡 2-8 工作區),修 SUMMARY #64(出自 掃描總表118/119)。中。修法規格來自內化卡,計畫在 docs/features/FR-114-2609-security-fix-dispatch/batches/plan-b2.md「卡 2-9」段。🔴 本卡要等第 1 批合回主線+套件發版後才能開工。
問題是什麼(白話)
SSP(系統安全計畫)刪除參考文件的兩個地方,都只檢查「操作者是不是這份計畫的管理者」,不檢查「這份文件是不是真的屬於這份計畫」——填錯或偽造文件 id 就能刪掉不相干計畫的文件。其中一處連查詢都用錯物件、查不到時還「補一個 None 繼續跑下去」,另一處對同一份文件的識別居然用了兩種不同的查詢方式。
首腦核對:
- 既有正確寫法可複製:module_frame_reference_document_service.py:147-151
- ssp_control_implementation_service.py:888-890 delete_reference_document 只檢查計畫管理者身分,沒有比對文件是否屬於這份計畫
- ssp_document_pool_service.py:123-129 delete_from_pool 問題更嚴重:檢查的物件本身就抓錯了,而且查不到對應文件時是「補一個 None 繼續執行」而不是報錯,另外對同一份文件用 file_uid 與 file_id 兩種不同查詢方式,兩者要收斂成一種
- 刪除動作可能連鎖觸發「引用計數歸零時真的刪除實體檔案」——本卡改動後要確認其他還在使用同一份文件的版本,引用計數邏輯不會被本卡的改動連帶弄壞
工作區
BE 側:接續卡 2-8 的工作區 /Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/.claude/worktrees/wt-fix-security(branch fix/security-b1),改 app/oscal/service/ 下的檔案,不要碰主 checkout,跑服務用 PORT=8001。
在哪裡
app/oscal/service/ssp_control_implementation_service.py:888-890 delete_reference_document,只檢查計畫管理者,補「文件是否屬於這份計畫」比對
app/oscal/service/ssp_document_pool_service.py:123-129 delete_from_pool,檢查物件抓錯、查無資料時補 None 繼續跑、file_uid 與 file_id 兩種查詢方式沒收斂,三個問題都要修
app/module_frame/service/module_frame_reference_document_service.py:147-151 既有正確寫法,直接複製這個 pattern
怎麼修
- ① ssp_control_implementation_service.py:888-890 delete_reference_document 補上「文件是否真的屬於這份計畫」的比對,比對邏輯複製 module_frame_reference_document_service.py:147-151 的既有正確寫法
- ② ssp_document_pool_service.py:123-129 delete_from_pool 三處問題一起修:改掉查詢用錯的物件;查不到對應文件時要報錯擋下,不能補一個 None 繼續往下跑;file_uid/file_id 兩種查詢方式收斂成一種,統一識別同一份文件的方式
- ③ 兩處都改完後,確認刪除連鎖觸發的「引用計數歸零才真的刪實體檔案」邏輯沒有被連帶破壞——特別是同一份文件被其他版本引用、計數還沒歸零時,不能被誤刪
手測
- DEV:計畫管理者身分,填入不屬於這份計畫的文件 id 嘗試刪除 → 期待被擋下(兩處都要測)
- DEV:計畫管理者身分,刪除真正屬於這份計畫的文件 → 期待正常成功
- DEV:ssp_document_pool_service.py 那處故意查無資料的情境 → 期待報錯擋下,不是靜默放行繼續執行