← SEARCHABLE ARCHIVE
Web · 2026-07-14

如何防止SQL注入?

用準備好的陳述和最低特權來辯護

INTERACTIVE READING MODE →

該部落格上撰寫的文章是出於教學目的而創建的。 另外,文章中的資訊可能不正確,請謹慎。

從輸入中刪除所有引號並不能阻止 SQL 注入。 SQL命令和使用者資料必須從一開始就分開,這樣資料就不會被解釋為命令。

使用準備好的語句

準備好的語句或參數化查詢分別標示了 SQL 語句中應放置值的位置。

const sql = 'SELECT id, name, password_hash FROM users WHERE name = ?';
const [rows] = await database.execute(sql, [userName]);

if (rows.length === 1)
{
    const passwordMatches = await passwordHasher.verify(
        rows[0].password_hash,
        password
    );
}

這裡?輸入的值是作為資料傳輸,而不是 SQL 語法。 如果使用者使用引號或OR即使輸入相同的字串,查詢結構也無法變更。

SQL 中的明文密碼不會進行比較。 在取得使用者資訊作為參數查詢後,將輸入值與儲存在經過驗證的密碼雜湊庫中的雜湊值進行比較。

使用 ORM 並不會自動讓一切變得更安全。 如果不使用ORM提供的參數函數將Raw Query組合成字串,也會出現同樣的漏洞。

表格名稱和排序標準根據允許清單進行檢查。

參數通常用於值。 表名、列名、ASC我DESC很多情況下,相同的SQL語法位置不能當作參數處理。

這些值不是作為使用者的字串貼上的,而是從伺服器預先確定的允許清單中選擇的。

const allowedSortColumns = {
    newest: 'created_at',
    name: 'name'
};

const sortColumn = allowedSortColumns[requestedSort] ?? 'created_at';
const sql = `SELECT id, name FROM users ORDER BY ${sortColumn} DESC`;

requestedSort將其轉換為伺服器擁有的安全字串,而不是將其本身放入 SQL 中,這一點很重要。

減少資料庫帳戶權限

如果向 Web 伺服器使用的資料庫帳戶授予管理員權限,則單一漏洞造成的損害可能會擴散到整個資料庫。

  • 僅執行搜尋的函數僅被授予讀取權限。
  • 僅存取您需要的表。
  • 不要使用 Web 應用程式帳戶執行資料庫管理任務。
  • 密碼不是以純文字形式存儲,而是使用經過驗證的雜湊方法。

錯誤會記錄在伺服器上並對使用者隱藏。

如果您按原樣傳回詳細的 SQL 錯誤,則可能會暴露表名或列名等內部結構。 應向使用者顯示一般失敗訊息,並應將詳細錯誤記錄在具有受控存取權限的伺服器日誌中。

輸入驗證、防火牆和偵測工具也可以提供協助。 但首先要做的就是參數化所有查詢,將動態輸入的 SQL 語法限制在白名單中,並最小化資料庫權限。