如何防止SQL注入?
用準備好的陳述和最低特權來辯護
該部落格上撰寫的文章是出於教學目的而創建的。 另外,文章中的資訊可能不正確,請謹慎。
從輸入中刪除所有引號並不能阻止 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 語法限制在白名單中,並最小化資料庫權限。