登入功能同時處理身分、密碼與 Session,一旦查詢邏輯被外部資料改變,影響通常比一般搜尋更大。這篇不教繞過真實登入,而是拆解錯誤查詢如何形成,並把認證設計修到正確。

本篇會學到什麼
- 理解帳號查詢與密碼驗證應分成兩個安全步驟
- 辨識把 Email 與密碼一起拼進 SQL 的風險
- 建立不洩漏帳號是否存在的回應與日誌
必備名詞與心智模型
安全登入不是『SQL 查到一列就算成功』。應先用參數化查詢依唯一識別資料取得帳號,再由專用密碼函式驗證雜湊,最後才建立 Session。資料庫不應保存明文密碼,也不該讓前端決定角色。
發生情境與生活化比喻
虛構商店的登入框收到 email 與 password。生活化比喻是櫃台先用名冊找到會員,再由獨立程序核對證件;不能讓訪客自己改寫名冊查詢規則。相同風險也會出現在管理後台、API token 查詢與忘記密碼流程。
不安全的原始碼
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
$sql = "SELECT id,role FROM users WHERE email='" . $email
. "' AND password='" . $password . "'";
$user = $pdo->query($sql)->fetch();
此片段刻意省略連線、路由與部署設定,只用來辨識資料流,請勿放入任何服務。
逐步看懂資料如何變成查詢
- 兩個 POST 值跨過 HTTP 信任邊界
- 程式把值、引號與 AND 條件組成同一字串
- 資料庫重新解析整段文字,無法分辨原始資料邊界
- 只要查詢結果非空,程式就錯誤地視為已完成認證
- 明文密碼與過大資料庫權限讓後果繼續擴大
修補後原始碼
$statement = $pdo->prepare(
'SELECT id,email,role,password_hash FROM users WHERE email=:email'
);
$statement->execute(['email' => $_POST['email'] ?? '']);
$user = $statement->fetch(PDO::FETCH_ASSOC);
$valid = $user && password_verify($_POST['password'] ?? '', $user['password_hash']);
if (!$valid) { /* 回傳統一的登入失敗訊息 */ }
修補的共同原則是先固定 SQL 結構,再把值獨立綁定;無法作為值綁定的識別字只能從程式內允許清單產生。
如何驗證修補
- 正確帳密成功,錯誤密碼與不存在帳號都回傳同一外部訊息
- Email 中的引號與 Unicode 不產生 SQL 錯誤
- Session ID 在登入後更新,角色只取自資料庫
- 日誌記錄事件 ID、來源與結果,但不記密碼
閱讀提醒:以下分析的目的,是讓你能在自己的程式、測試資料與授權環境中辨識風險。面對正式系統時,先取得明確授權並保存變更紀錄;不要用錯誤訊息或一次回應就推論資料外洩,也不要把文章中的概念改造成自動化探測。安全工作的完成條件,是能說明根因、修補位置、回歸結果與剩餘風險。
更多應用情境、常見誤判與觀察方法
把原理放回真實開發情境
登入應先依帳號取回單一使用者,再用密碼雜湊驗證;驗證成功後才建立 Session。 實作時不要只盯著畫面上的輸入框,還要檢查 API 參數、伺服器端預設值、資料轉換與最後呼叫的資料庫介面。最實用的閱讀方式,是把每一段程式標成「外部來源、轉換、控制、資料庫 sink」,確認資料值沒有在途中重新變回 SQL 結構。
常見誤判
把錯誤訊息改成『帳號或密碼錯誤』只能減少枚舉,不能修補字串拼接。 安全判斷不能只靠畫面、單次錯誤或某一個防護產品;應同時看原始碼、驅動程式實際執行方式、資料庫權限與回歸測試。若無法證明查詢結構固定,就應把它視為待修的設計風險。
開發與 SOC 可以觀察什麼
監控同來源短時間大量失敗、不同帳號輪詢與異常查詢錯誤,但避免把密碼寫入日誌。 日誌宜記錄時間、路由、請求關聯 ID、查詢名稱、結果狀態與耗時,敏感值則遮罩或雜湊。偵測規則的用途是縮短發現時間;阻擋之後仍須回到程式碼修補,並搜尋其他共用元件與相同資料流。
審查時的三個追問
- 這個值最早由誰控制,經過哪些轉換?
- 它在資料庫呼叫中是資料值,還是欄位、排序、運算式等結構?
- 若預防失效,最小權限、監控與事件流程能限制並發現多少影響?
開發與維運防禦清單
- 使用 password_hash/password_verify,不自製密碼雜湊
- 登入查詢只需 SELECT,帳號不可擁有 DDL 權限
- 速率限制與 MFA 降低撞庫風險,但不能取代參數化
- 審查忘記密碼、SSO callback 與後台登入的相同資料流
重點整理與下一篇
登入框顯示了值參數的典型防禦。下一篇會處理搜尋、篩選、排序與分頁,特別說明為什麼欄位名不能直接用 placeholder。
參考資料與更新日期
更新日期:2026-07-20














