【資安】SQL Injection (SQL 注入)

RA-Paul
4 min readMay 26, 2024

--

Icon made by Freepik from www.flaticon.com

基本介紹

最近正在學習相關的資安知識,通常一個網頁的漏洞不會是只有一個地方出現問題,而是從不同地方、不同階層所堆疊起來的,本系列文章會記錄幾個常見的 Web 資安問題,並且解釋其原理與如何防範。

SQL Injection 介紹

SQL Injection 主要是發生於開發人員對於使用者輸入的資訊處理不當,導致SQL 語句中混入人為惡意的語句,從而讓駭客獲得或修改資料庫數據。

如果只是一般登入(如下圖),並不會有任何問題

帳號若是輸入 ' OR 1=1 --,在沒有防範的情況下,我們變成就會執行下方語句,透過 ' 先結束第一個條件,再透過 OR 1=1 來將條件全變成 true,最後使用--來註解後方語句,導致駭客可以獲取到全部資料,此時要是沒有其他防範,可能就會成功登入了。

SELECT * FROM users WHERE username='' OR 1=1 --' AND password=paul

帳號若是輸入 '; DROP TABLE users; -- ,則會先結束查詢後,同時又去將 users 這張表刪除掉,當然也可以抽換 DROP TABLE users; 成為駭客想執行的語句。

SELECT * FROM users WHERE username=''; DROP TABLE users; --' AND password=paul

防範方法

Escape Parameters (參數轉譯)

透過 mysqli 中的 real_escape_string 方法,我們可以對部分內容文字進行轉譯,例如將 ' 變成 \' 來告知我們的程式說該處' 為文字的一部分,透過這樣的傳換就能避免有心人士竄改 SQL 語句

// 連接到資料庫
$mysqli= new mysqli('localhost', 'username', 'password', 'database');

$username = "' OR 1=1 --";
$username = $mysqli->real_escape_string($username);
// \' OR 1=1 --

Query Parameterization (查詢參數化)

透過參數化的 SQL 語句,其將語句與參數兩個分開設定,避免掉在文字組合上導致的錯誤,在執行時也會先編譯完 SQL 指令後才帶入參數,因此較不用擔心惡意 SQL 語句參入其中

// 連接到資料庫
$mysqli = new mysqli('localhost', 'username', 'password', 'database');

// 使用預處理語句和綁定參數
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();

ORM

改使用 ORM 來代替原先的 SQL 語句,各框架的 ORM 都有對於 SQL Injection 進行防範。

// 使用 Eloquent ORM 查詢用戶
$user = User::where('username', $username)
->where('password', $password)
->first();

最後就是要設定相對應的權限,來限縮受到傷害的範圍。

--

--

RA-Paul

全端工程師,分享我在學習的路上所遇過的技術與困難