1. 程式人生 > >PHP SQL防注入

PHP SQL防注入

參考資料:

PHP中防止SQL注入的方法
php操作mysql防止sql注入(合集)
PDO防注入原理分析以及使用PDO的注意事項
php SQL 防注入的一些經驗
如何在PHP中防止SQL注入?
PHP安全程式設計:防止SQL注入
addslashes與mysql_real_escape_string的區別
How can I prevent SQL injection in PHP?

什麼是SQL注入?

Sql注入,是通過程式設計師程式設計時的疏忽,經過查詢sql注入的位置、判斷伺服器型別和後臺資料型別、針對不同型別的伺服器以及資料庫進行攻擊,實現無賬號登入,甚至篡改資料庫。

解決方法

1.魔術函式 addslashes

Addslashes()是與stripslashes()是功能相反的函式。
Addslashes()用於給變數中的’ ” 與null新增反斜槓\,用於避免傳入sql語句的引數格式錯誤,同時如果有人注入子查詢,通過加可以將引數解釋為內容,而非執行語句,避免被mysql執行。
Addslashes()只在PHP中執行,\是不會寫入mysql中的。
當 PHP 指令 magic_quotes_sybase 被設定成 on 時,意味著開啟addslashes()。
在PHP5.4.0版本之前,magic_quotes_sybase 預設開啟。
可以通過函式get_magic_quotes_gpc()判斷magic_quotes_gpc是否開啟。

if (!get_magic_quotes_gpc()) {
		$lastname = addslashes($_POST[‘lastname’]);
	} else {
		$lastname = $_POST[‘lastname’];
	}

但是addslashes()並不會檢測字符集,比如如果是gbk編碼,可能會將某些字元解釋成兩個ASCII位元組,造成新的注入風險。Utf沒有這個問題。

2.mysql_real_escape_string

mysql_real_escape_string()與addslashes()相比,不僅會將’ " NOL(ascii的0)轉義,還會把r n進行轉義。同時會檢測資料編碼。
mysql_real_escape_string()使用時需要進行資料庫的連線,因為要獲取資料庫的字符集,如果當前不存在連線,會使用上一次連線。
這個函式在PHP5.5.0不被推薦使用,PHP7.0被廢棄

3.預處理 (Prepared Statements) ---- mysqli:prepare()

Mysqli的引數化繫結

$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'world');
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
$stmt->bind_param('sssd', $code, $language, $official, $percent);

在這裡插入圖片描述

mysqli=newmysqli("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();

Mysqli預處理查詢是將一步查詢分作兩步操作
A 寫sql語句,用?佔位,替代sql中的變數
B 替換變數
C 執行SQL語句
D 得到一個二進位制結果集,從二進位制結果中取出php結果集
E 遍歷結果集

4.預處理 (Prepared Statements) ---- PDO

使用PDO引數化繫結
類似於mysqli也是分兩步預處理

$pdo = new PDO("mysql:host=192.168.0.1;dbname=test;charset=utf8","root");
$st = $pdo->prepare("select * from info where id =? and name = ?");
 
$id = 21;
$name = 'zhangsan';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
 
$st->execute();
$st->fetchAll();

PHP將sql模板和變數兩次傳送給mysql,由mysql進行變數的轉義處理。
PHP版本不同,有不同的處理方式。
PHP版本小於5.3.6,需要關閉PHP使用本地模擬prepare
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
PHP版本為5.3.6+的,請在在PDO的DSN中指定charset屬性
因為PHP5.3.6版本之前,並不支援PDO的DSN charset設定

總結

控制注入主要分三個方面:
1.做引數合法性,特殊字元,長度校驗
2.資料庫中嚴格設定引數型別,沒必要用字串型別的,就少用,不得已使用可以控制字元長度;能用int,bool之類的就用此種類型
3.操作SQL採用引數化(parameter)