通過把sql命令插入到web表單遞交或輸入域名或頁面請求的查詢字符串,最終達(dá)到欺騙服務(wù)器執(zhí)行惡意的sql命令。具體來說,它是利用現(xiàn)有應(yīng)用程序,將(惡意)的sql命令注入到后臺數(shù)據(jù)庫引擎執(zhí)行的能力,得到一個存在安全漏洞的網(wǎng)站上的數(shù)據(jù)庫。
SQL Injection,SQL 注入,其實(shí)就是利用代碼漏洞改變 SQL 的語意,從而形成惡意 SQL 語句
$username?=?$_POST['username']; $password?=?$_POST['password']; $query?=?"select?*?from?users?where?username?=?'{$username}'?and?password?=?'{$password}'"; //?判斷是否登錄成功 if?(DB::select($query))?{ ????return?true; } return?false;
咋一看這段偽代碼沒啥問題,就是判斷賬號密碼是否正確,正確就返回 true,允許登錄。但是如果傳入的 username 為 123′ or 1=1;#,那么 SQL 語句就變?yōu)榱?/p>
select?*?from?users?where?username?=?'123'?or?1=1; #?and?password?=?'{$password}'";
這條惡意的 SQL 語句無論何時都會返回 true,因?yàn)?1=1
通過 ORM 注入
我們前面講過 SQL Injection 就是利用代碼漏洞改變 SQL 的語意,意味著 ORM 也是一個潛在的注入點(diǎn)。以 tp3.2 為例,有下面這段代碼
$result?=?D('User')->where([ ????'username'?=>?$_POST['username'], ????'password'?=>?$_POST['password'], ]); if?($result)?{ ????echo?'登錄成功'; }?else?{ ????echo?'登錄失敗'; }
這段代碼咋看起來沒啥問題,但是如果 username 傳入的是 username[0]=neq&username[1]=1111,這樣就是的查詢語句變?yōu)?/p>
$result?=?D('User')->where([ ????'username'?=>?['neq',?111], ????'password'?=>?$_POST['password'], ]);
那么 $result 的結(jié)果將永遠(yuǎn)為 true
防范方法
-
對傳入的參數(shù)進(jìn)行數(shù)據(jù)類型判斷和數(shù)據(jù)類型轉(zhuǎn)換
-
對引號進(jìn)行轉(zhuǎn)義,php 可以使用 addslashes,mysql_real_escape_string 等函數(shù)
-
預(yù)處理語句,最有效防范 SQL Injection
-
代碼審計(jì)
預(yù)處理語句是如何防止 SQL Injection 的
預(yù)處理語句是由數(shù)據(jù)庫實(shí)現(xiàn)的,比如 MySQL 就有實(shí)現(xiàn)預(yù)處理語句。首先講下預(yù)處理的基本流程
-
MySQL 接收到 預(yù)處理 SQL Template,立刻著手進(jìn)行解析(詞法和語法)
-
客戶端發(fā)送數(shù)據(jù),去替換 SQL Template 中的占位符(?)
-
MySQL 執(zhí)行語句,返回結(jié)果
-
刪除預(yù)處理語句(可選)
那么預(yù)處理語句是如何防范 SQL 注入的呢?首先所謂的 SQL Injection 就是強(qiáng)行去改變 SQL 語意。而在步驟一中已經(jīng)處理完成語句,將 SQL 的語意固定下來,步驟二的替換占位符并不會改變 SQL 語意。下面是 PHP pdo 的例子
$stmt?=?$pdo->prepare("select?*?from?users?where?username?=?'?'?and?password?=?'?'"); $stmt->execute("123'?or?1=1;#",?'test');
相關(guān)推薦:《mysql教程》