PostgreSQL 擁有強型別、豐富運算子、JSON 與擴充能力;這些能力不會自動防止注入。libpq 的 PQexecParams、語言驅動的參數 API 與固定 schema 設計才是安全邊界。

本篇會學到什麼
- 理解 PostgreSQL 的 $1 參數與明確型別 cast
- 分辨 value parameter 與 identifier escaping
- 審查 search_path、函式權限與資料庫角色
必備名詞與心智模型
PostgreSQL 官方文件指出 PQexecParams 可將參數值與 command string 分開,而且一次只允許一個 SQL command,這可作額外防線。參數仍只代表值;表名或欄位名需要重設計、固定 mapping,或在必要時使用驅動提供的 identifier API。
發生情境與生活化比喻
API 查詢 JSONB 商品屬性並依日期排序。開發者可能把 JSON path、排序欄位或 tenant schema 直接插入 SQL。即使普通 category 值已使用 $1,其他結構位置仍要逐一審查。
不安全的原始碼
const text = `SELECT id,name FROM products
WHERE attributes->>'color' = '${color}'
ORDER BY ${sort}`;
const result = await client.query(text);
此片段刻意省略連線、路由與部署設定,只用來辨識資料流,請勿放入任何服務。
逐步看懂資料如何變成查詢
- color 與 sort 來自 API
- 兩者透過 JavaScript template literal 進入 command text
- PostgreSQL parser 解讀 JSONB 運算式與 ORDER BY
- 參數化其中一個值不會保護另一個識別字
- 角色的 schema/function 權限限制最大影響
修補後原始碼
const allowedSorts = { newest: 'created_at DESC', name: 'name ASC' };
const orderBy = allowedSorts[sort] ?? allowedSorts.newest;
const text = `SELECT id,name FROM products
WHERE attributes->>'color' = $1::text ORDER BY ${orderBy}`;
const result = await client.query(text, [color]);
修補的共同原則是先固定 SQL 結構,再把值獨立綁定;無法作為值綁定的識別字只能從程式內允許清單產生。
如何驗證修補
- 每個外部值都有獨立 $n 參數
- 型別不明的位置使用明確 cast,而非串接型別字串
- sort 與 tenant 只能映射已知值
- search_path 固定且函式使用最小必要 SECURITY 設定
- 角色不能建立不需要的 extension 或 schema object
閱讀提醒:以下分析的目的,是讓你能在自己的程式、測試資料與授權環境中辨識風險。面對正式系統時,先取得明確授權並保存變更紀錄;不要用錯誤訊息或一次回應就推論資料外洩,也不要把文章中的概念改造成自動化探測。安全工作的完成條件,是能說明根因、修補位置、回歸結果與剩餘風險。
更多應用情境、常見誤判與觀察方法
把原理放回真實開發情境
PostgreSQL 使用 $1 等參數、明確型別與受限 Role;Schema 搜尋路徑也要納入權限設計。 實作時不要只盯著畫面上的輸入框,還要檢查 API 參數、伺服器端預設值、資料轉換與最後呼叫的資料庫介面。最實用的閱讀方式,是把每一段程式標成「外部來源、轉換、控制、資料庫 sink」,確認資料值沒有在途中重新變回 SQL 結構。
常見誤判
ORM、函式或 dollar-quoted 字串不是安全保證;動態 EXECUTE 仍需安全組合。 安全判斷不能只靠畫面、單次錯誤或某一個防護產品;應同時看原始碼、驅動程式實際執行方式、資料庫權限與回歸測試。若無法證明查詢結構固定,就應把它視為待修的設計風險。
開發與 SOC 可以觀察什麼
關聯 statement fingerprint、角色、schema、錯誤碼與延遲,避免在公開回應暴露內部物件名稱。 日誌宜記錄時間、路由、請求關聯 ID、查詢名稱、結果狀態與耗時,敏感值則遮罩或雜湊。偵測規則的用途是縮短發現時間;阻擋之後仍須回到程式碼修補,並搜尋其他共用元件與相同資料流。
審查時的三個追問
- 這個值最早由誰控制,經過哪些轉換?
- 它在資料庫呼叫中是資料值,還是欄位、排序、運算式等結構?
- 若預防失效,最小權限、監控與事件流程能限制並發現多少影響?
開發與維運防禦清單
- 優先使用 driver parameter API,不手動 quote literal
- identifier 必須使用固定 mapping 或正確 identifier API
- 限制 role、schema 與 function execute 權限
- 追蹤 statement fingerprint、錯誤率與異常長查詢
重點整理與下一篇
下一篇合併比較 Oracle 與 SQLite:一個是企業級資料庫,一個是嵌入式引擎,但兩者都必須把資料與 SQL 結構分離。
參考資料與更新日期
更新日期:2026-07-20













