php操作mysql防止sql注入(合集)
本文將從sql注入風險說起,並且比較addslashes、mysql_escape_string、mysql_real_escape_string、mysqli和pdo的預處理的區別。
當一個變數從表單傳入到php,需要查詢mysql的話,需要進行處理。
舉例:
$unsafe_variable = $_POST['user_input'];
mysqli_query("INSERT INTO table (column) VALUES ('" . $unsafe_variable . "')");
使用者可以輸入諸如 : value'); DROP TABLE table;-- ,SQL語句就變成這樣了:
INSERT INTO table (column) VALUES('value'); DROP TABLE table;--')
執行的結果就是table表被刪掉了。
這是一種常見的sql注入方法,那麼在程式中,應該怎樣預防呢?
1.魔術引用 (推薦指數3)
addslashes()與stripslashes()是功能相反的函式。
addslashes()用於對變數中的' " 和NULL新增斜槓,用於避免傳入sql語句的引數格式錯誤,同時如果有人注入子查詢,通過加可以將引數解釋為內容,而非執行語句,避免被mysql執行。
不過,addslashes()新增的只在php中使用,並不會寫入mysql中。
那麼,tripslashes()的作用是將加了的php變數去掉,由於不會寫入mysql中,所以從mysql查詢出來的內容不需要再tripslashes()。
在防注入方面,addslashes()可以防止掉大多數的注入,但是此函式並不會檢查變數的編碼,當使用例如中文gbk的時候,由於長度比較長 ,會將某些gbk編碼解釋成兩個ascii編碼,造成新的注入風險(俗稱寬位元組注入)。見下面2。
如果從網頁表單、php、mysql都使用utf8編碼,則沒有這個問題。
基於此函式的風險,並不建議使用,推薦使用下面3中的方法。
https://segmentfault.com/q/10...
2. mysql_real_escape_string() (推薦指數4)
由於addslashes()不檢測字符集,所以有寬位元組注入風險,所以php中新增了這個函式。
這個函式本來是mysql的擴充套件,但是由於存在寬位元組的問題,php基於mysql的擴充套件開發了此函式。
gbk寬字元漏洞導致的sql注入
https://www.91ri.org/8611.html
http://www.cnblogs.com/suihui...
mysql_real_escape_chars()是mysql_escape_chars()的替代用法。
與addslashes()相比,不僅會將' " NOL(ascii的0)轉義,還會把r n進行轉義。同時會檢測資料編碼。
按php官方的描述,此函式可以安全的用於mysql。
此函式在使用時會使用於資料庫連線(因為要檢測字符集),並根據不同的字符集做不同的操作。如果當前連線不存在,剛會使用上一次的連線。
mysql_real_escape_string()防注入詳解
此方法在php5.5後不被建議使用,在php7中廢除。
參考:https://segmentfault.com/q/10...
3.預處理查詢 (Prepared Statements) (推薦指數5)
使用prepared statements(預處理語句)和引數化的查詢,可以有效的防止sql注入。
為什麼預處理和引數化查詢可以防止sql注入呢?
在傳統的寫法中,sql查詢語句在程式中拼接,防注入(加斜槓)是在php中處理的,然後就發語句傳送到mysql中,mysql其實沒有太好的辦法對傳進來的語句判斷哪些是正常的,哪些是惡意的,所以直接查詢的方法都有被注入的風險。
在mysql5.1後,提供了類似於jdbc的預處理-引數化查詢。它的查詢方法是:
- 先預傳送一個sql模板過去
- 再向mysql傳送需要查詢的引數
就好像填空題一樣,不管引數怎麼注入,mysql都能知道這是變數,不會做語義解析,起到防注入的效果,這是在mysql中完成的。
參考:
PHP中如何防止SQL隱碼攻擊
http://blog.csdn.net/sky_zhe/...
引數化查詢為什麼能夠防止SQL隱碼攻擊
http://www.cnblogs.com/LoveJe...
上面提供的資料比較多,下面根據自己的理解整理出來。
預處理分為兩種:
A.使用mysqli:prepare()實現
看一個完整的用法:
$mysqli = new mysqli("example.com", "user", "password", "database");
$stmt = $mysqli->prepare("SELECT id, label FROM test WHERE id = ?");
$stmt->bind_param(1, $city);
$stmt->execute();
$res = $stmt->get_result();
$row = $res->fetch_assoc();
a.寫sql語句,然後用?佔位符替代sql中的變數
b.替換變數
c.執行
d.得到一個二進位制結果集,從二進位制結果中取出php結果集
e.遍歷結果集
使用預處理,一條查詢分兩步,所以很安全。也是php5.5及php7推薦方法。
參考:
http://www.cnblogs.com/liuzha...
B. 使用pdo實現
pdo是一個php官方推薦的資料庫抽象層,提供了很多實用的工具。
使用pdo的預處理-引數化查詢可以有效防止sql注入。
使用方法跟上面差不多,區別在於pdo提供了更多樣的方法。
使用這個pdo->$stmt物件進行查詢後,會被結果集覆蓋,型別是一個二維陣列。
我們在上面預處理-引數化查詢是在mysql中進行防注入操作的,其實pdo也內建了一個預處理的模擬器,叫做ATTR_EMULATE_PREPARES。
預設情況下,PDO會使用DSN中指定的字符集對輸入引數進行本地轉義(PHP手冊中稱為native prepared statements),然後拼接成完整的SQL語句,傳送給MySQL Server。這有些像我們平時程式中拼接變數到SQL再執行查詢的形式。
這種情況下,PDO驅動能否正確轉義輸入引數,是攔截SQL隱碼攻擊的關鍵。然而PHP 5.3.6及老版本,並不支援在DSN中定義charset屬性(會忽略之),這時如果使用PDO的本地轉義,仍然可能導致SQL隱碼攻擊,
如果ATTR_EMULATE_PREPARES=true(預設情況),預處理-引數化查詢在pdo的模擬器中完成,模擬器根據字符集(dsn引數)進行處理,然後把語句傳送給mysql。
如果ATTR_EMULATE_PREPARES=false,sql會分兩次把引數給送給mysql,mysql根據自身的字符集(set names <charset>)進行處理,完成查詢。
但由於各版本差異,pdo在各版本中的實現程度也不一樣,有些版本還有bug,我們以php5.3.6做為分界線來進行說明:
php5.3.6以下版本
$pdo = new PDO("mysql:host=localhost;dbname=test;",'root','pwd');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
$pdo->exec('set names utf8');
$id = '0 or 1 =1 order by id desc';
$sql = "select * from article where id = ?";
$statement = $pdo->prepare($sql);
$statement->bindParam(1, $id);
$statement->execute();
如上,我們關閉了本地預處理模擬器,引數會直接分批傳送給mysql,由mysql根據set name utf8字符集進行檢測,完成sql注入處理。以上程式碼不會產生注入。
php5.3.6以上版本
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8",'root','pwd');
$pdo->exec('set names utf8');
$id = '0 or 1 =1 order by id desc';
$sql = "select * from article where id = ?";
$statement = $pdo->prepare($sql);
$statement->bindParam(1, $id);
$statement->execute();
在php5.3.6以上版本中,預設情況下ATTR_EMULATE_PREPARES開啟,模擬器會根據new PDO()中的charset=utf8進行檢測,在模擬器上完成防注入操作。如果把模擬器關閉,也會像低版本一樣送交mysql進行防注入處理。
參考:
PDO防注入原理分析以及使用PDO的注意事項
http://zhangxugg-163-com.itey...
PHP 5.3.6及以前版本的PDO的bindParam,bindValue潛在的安全隱患
http://zhangxugg-163-com.itey...
再論php 5.3.6以前版本中的PDO SQL隱碼攻擊漏洞問題
http://my.oschina.net/zxu/blo...
segmentfault討論
https://segmentfault.com/q/10...
- html輸出與防止xss注入
特殊字元輸出
比如' " < >有著特殊的意義,如果直接寫到html中輸出,會引起dom格式的錯亂,那麼就需要用到特殊的輸出方法。
htmlspecialchars()
用於將一些特殊符號轉義成只有瀏覽器識別的轉義符。
舉個例子:
$a = " ' ";
<input type="test" value='<?=$a;?>'>
<textarea><?=$a;?></textarea>
上面由於$a的值就是一個' ,當它輸出在value=''之間時,會破壞html原有的dom格式,導致html解析錯誤。
下面那個'輸出在標籤對之間時沒有問題。
上面那個問題怎麼解決呢? 可以這樣:
<input type="test" value='<?php echo htmlspecialchars($a);?>'>
php會向瀏覽器輸出:
<input type="test" value='&qouts;'>
這個符號只有流量器認識,原始碼中看到是這樣,但是瀏覽器輸出的就是一個'號。
xss注入
xss也就是常說的跨域攻擊,這是一種在客戶端瀏覽器上面執行的攻擊。
比如在表單或者url引數中,人為寫入javascript程式碼,看起來是普通的文字,但是被瀏覽器解析後變成可執行的javascript動作,用來做廣告或者攻擊等等。
舉例:
有人在發貼的時候寫入了javascript程式碼,一開啟就彈視窗。
<script type="text/javascript">alert("你是我的小蘋果!");</scirpt>
對於這種惡意的東西,為了力求安全,我們即可以在發貼前對可用的html程式碼進行過濾,也可以用htmlspecialchars()進行轉義。
轉義後alert()內容變成:
alert("你是我的小蘋果!");
雖然看到的文字不變,但是由於轉義了,這個alert()只會以文字顯示,而不會執行彈窗。
http://netsecurity.51cto.com/...
總結:
1.建議將升級到php 5.3.9+ php 5.4+,php 5.3.8存在致命的hash碰撞漏洞。
2.不要使用基礎的php拼接sql語句直接查詢,避免使用addslashes()和mysql_real_escape_string()防止注入。
3.推薦使用mysqli或pdo的預處理-引數化查詢。
4.pdo預設會使用自帶的ATTR_EMULATE_PREPARES模擬器處理sql語句,php5.3.6以下版本使用預處理-引數化時,設定dsn引數(setcahrs=utf8)沒用的(可能是bug),所以防注入還是有缺陷。應將模擬器關閉,pdo會把sql交由mysql進行防注入。
5.php5.3.6以上版本,應設定dsn引數(setchars=utf8),預設就可以在模擬器防注入。也可以手工關掉模擬器,效果跟上面第4步一樣。
相關文章
- 防止sql注入SQL
- 如何有效防止sql注入SQL
- Python 防止sql注入的方法PythonSQL
- JDBC 如何有效防止 SQL 注入JDBCSQL
- PHP 安全輸入輸出方式 「防止 XSS 注入」PHP
- PHP+MySQL 手工注入語句大全PHPMySql
- PHP獲取IP地址的方法,防止偽造IP地址注入攻擊PHP
- PHP操作MySQL資料庫PHPMySql資料庫
- SQL 注入SQL
- sql注入SQL
- SQL 注入:聯合注入SQL
- sql注入之union注入SQL
- 防止SQL注入的五種方法
- js 操作合集JS
- sql注入修改SQL
- sql注入1SQL
- sql注入2SQL
- PHP面試合集PHP面試
- MySql常用操作SQL語句彙總MySql
- NSSCTF———Web(sql注入)WebSQL
- sql注入——盲注SQL
- XSS 和 SQL 注入SQL
- sql注入之型別及提交注入SQL型別
- sql注入之堆疊注入及waf繞過注入SQL
- 理解php物件注入PHP物件
- 封神臺MYSQL 注入 - Dns注入MySqlDNS
- PHP 原生操作 Mysql 分頁資料案例PHPMySql
- MySql注入科普MySql
- mysql防注入MySql
- 二次注入(SQL)SQL
- sql聯合注入原理SQL
- pick靶場-sql注入SQL
- SQL MAP 注入測試SQL
- 墨者學院-SQL手工注入漏洞測試(MySQL資料庫)MySql資料庫
- MySQL工具之binlog2sql閃回操作MySql
- php簡單操作mysql資料庫的類PHPMySql資料庫
- 你想不到的最簡單php操作MySQLPHPMySql
- PHP 防止表單重複提交PHP