核心原則:纵深防禦
保護資料庫的措施與層級越多,攻擊者竊取/濫用機敏資料的機率越低。設計階段即應落實最小權限、參數化查詢、加密儲存等機制。
資料庫帳號規劃
- 應用程式**嚴禁**使用 root/superuser 連線。
- 依功能模組建立專用帳號,僅授予必要權限(SELECT/INSERT/UPDATE/DELETE),拒絕 DDL(DROP/ALTER)與管理權限。
- 不同業務情境使用不同帳號,限制單一帳號洩露的影響範圍。
連線加密
- 啟用 SSL/TLS 加密 Client-Server 傳輸,防竊聽。
- 或使用 SSH Tunnel 封裝資料庫連線。
靜態資料加密
SSL 僅保護傳輸中資料,資料庫檔案本身若被竊取仍可讀取。對策:
- 應用層加密敏感欄位(如密碼、身分證、信用卡),使用 PHP
mcrypt/openssl 或 hash_hmac。
- 密碼**必須**儲存雜湊值(如
password_hash()、bcrypt、PBKDF2),嚴禁明文或單純 MD5/SHA1。
SQL 注入攻擊實例與防範
典型注入向量
// 未驗證 $offset 直接拼接
$query = "SELECT * FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// 攻擊載荷:0; UPDATE user SET Password=PASSWORD('crack') WHERE user='root'; FLUSH PRIVILEGES;--
防禦措施
- 參數化查詢 / Prepared Statements(PDO、mysqli):
$stmt = $pdo->prepare('SELECT * FROM products ORDER BY name LIMIT 20 OFFSET :offset'); $stmt->execute(['offset' => $offset]);
- 輸入驗證與型別轉換:
settype($offset, 'integer'); // 或 (int)$offset
- 字串輸入轉義(若不可用 Prepared Statement):
$safe = $mysqli->real_escape_string($input);
- 最小權限帳號:即使注入成功,攻擊者也無法執行 DDL 或存取其他資料庫。
- 錯誤訊息不外洩:關閉
display_errors,記錄至日誌供內部排查。
- 資料庫審計日誌:記錄所有查詢,事後可追蹤異常活動。
進階攻擊:UNION 注入、UPDATE 注入、OS 指令執行
- UNION 注入可列出任意表資料(如密碼表),防禦同樣靠參數化查詢。
- UPDATE 注入可竄改管理者權限欄位,防禦靠欄位白名單 + Prepared Statement。
- MSSQL
xp_cmdshell 等危險擴展預設應關閉,資料庫服務帳號不應具備 OS 管理權限。
程式碼審查檢查表
- 所有動態 SQL 是否使用 Prepared Statement?
- 數值型參數是否強制轉型?
- 字串參數是否經過正規化/轉義?
- 資料庫連線帳號是否為最小權限專用帳號?
- 錯誤回應是否隱藏結構細節?
- 敏感欄位是否加密/雜湊儲存?