PDO防止SQL注入詳細(xì)介紹
使用PDO訪問MySQL數(shù)據(jù)庫時(shí)畔咧,真正的real prepared statements 默認(rèn)情況下是不使用的。為了解決這個(gè)問題敷鸦,你必須禁用 prepared statements的仿真效果恋捆。下面是使用PDO創(chuàng)建鏈接的例子:
復(fù)制代碼 代碼如下:
$dbh = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setAttribute()這一行是強(qiáng)制性的,它會告訴 PDO 禁用模擬預(yù)處理語句伤疙,并使用 real parepared statements 。這可以確保SQL語句和相應(yīng)的值在傳遞到mysql服務(wù)器之前是不會被PHP解析的(禁止了所有可能的惡意SQL注入攻擊)。雖然你可以配置文件中設(shè)置字符集的屬性(charset=utf8)徒像,但是需要格外注意的是黍特,老版本的 PHP( < 5.3.6)在DSN中是忽略字符參數(shù)的。
我們來看一段完整的代碼使用實(shí)例:
復(fù)制代碼 代碼如下:
$dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的仿真效果
$dbh->exec("set names 'utf8'");
$sql="select * from test where name = ? and password = ?";
$stmt = $dbh->prepare($sql);
$exeres = $stmt->execute(array($testname, $pass));
if ($exeres) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
print_r($row);
}
}
$dbh = null;
上面這段代碼就可以防范sql注入锯蛀。為什么呢灭衷?
當(dāng)調(diào)用 prepare() 時(shí),查詢語句已經(jīng)發(fā)送給了數(shù)據(jù)庫服務(wù)器谬墙,此時(shí)只有占位符 ? 發(fā)送過去今布,沒有用戶提交的數(shù)據(jù);當(dāng)調(diào)用到 execute()時(shí)拭抬,用戶提交過來的值才會傳送給數(shù)據(jù)庫,他們是分開傳送的侵蒙,兩者獨(dú)立的造虎,SQL攻擊者沒有一點(diǎn)機(jī)會。
但是我們需要注意的是以下幾種情況纷闺,PDO并不能幫助你防范SQL注入
1算凿、你不能讓占位符 ? 代替一組值,如:
復(fù)制代碼 代碼如下:
SELECT * FROM blog WHERE userid IN ( ? );
2犁功、你不能讓占位符代替數(shù)據(jù)表名或列名氓轰,如:
復(fù)制代碼 代碼如下:
SELECT * FROM blog ORDER BY ?;
3、你不能讓占位符 ? 代替任何其他SQL語法浸卦,如:
復(fù)制代碼 代碼如下:
SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog;