安全守則
這是第三方資源必須遵守的安全守則。這裡的項目都來自實際發生過的事故類型。
輸出:XSS
- 輸出使用者輸入時,請一律使用
{{ }}(跳脫)。 {!! !!}請只用於核心已淨化的 HTML(編輯器內文getContent())。一旦放入未淨化的值,就是 XSS。- 在 JS 情境中放入值時,請使用
@json($value)或|escapejs篩選器。請勿以字串串接的方式產生指令碼。
輸入:在伺服器端驗證
- 畫面(JS)上的驗證只是為了方便。所有驗證都要在 proc 動作(伺服器)中再做一次。
- 數字請以
(int)轉型,有允許清單的值請用in_array(..., true)確認。 - 只要使用查詢 XML 的繫結,就能防止 SQL 注入,但請再以
filter="number"與notnull加強一層。為避免產生沒有條件的 update/delete,關鍵條件務必加上 notnull。
CSRF 與動作設計
- 會變更資料的動作,務必以 proc 動作 + POST 實作。核心會自動檢查 CSRF 權杖。
- 不可在 GET(disp)中變更資料。只要一個連結就能執行刪除的結構,也會繞過 CSRF 檢查。
- 只有外部伺服器呼叫的回呼才加上
standalone="true" check-csrf="false",並在該動作中進行自行驗證(簽章・狀態權杖・伺服器間再確認)。請勿信任經由瀏覽器傳來的值。
權限確認
- 不要只依賴 module.xml 的
permission屬性,需要確認擁有者的動作(修改自己的文章等)請在動作中比對member_srl。 - 管理功能請以
permission="manager"+ 畫面上的權限分流,設下兩道關卡。只在畫面上隱藏按鈕並不算是保護。
檔案上傳
- 副檔名請以允許清單方式檢查(禁止清單會被繞過)。
- 設定大小限制,儲存的檔名不要沿用原始檔名,請重新產生。
- 為避免可執行的檔案(.php 等)在上傳路徑中被執行,請使用核心檔案模組的路徑(
files/attach)。網頁伺服器設定會封鎖此路徑的 PHP 執行。
機密值的保管
- 將權杖・金鑰存入 DB 時,請以雜湊(供查詢用)或加密(需要解密時)方式儲存。核心的
Zittme\Framework\Security提供加密工具。 - 若在
files/cache下建立暫存狀態檔,請確認無法從網頁直接存取。若是網頁伺服器封鎖規則中沒有的新路徑,就必須新增規則。實際上曾發生此路徑以 HTTP 200 被公開的事故。 - 請勿將認證資訊寫死在程式碼中。請儲存在模組設定(insertModuleConfig)中,並在畫面上以遮罩方式顯示。
外部串接
- 我方伺服器接收的回呼:請勿信任經由瀏覽器的值,改以伺服器間通訊重新驗證(付款金額、驗證結果等)。
- 交換授權碼時,請使用狀態權杖(state)與 PKCE 等標準保護機制。
- 請確認回應中沒有送出不必要的 Set-Cookie。若在跨網站回呼中重新核發工作階段 Cookie,可能會覆蓋使用者既有的工作階段。
最後檢查清單
- 是否有使用者輸入未經跳脫就輸出的地方
- 是否有不經 proc、以 GET 變更資料的地方
- 是否有沒有條件的 update/delete 查詢
- 伺服器端是否有上傳副檔名・大小檢查
- 機密值是否以明文儲存,或位於可從網頁存取的路徑