《PHP學習:PDO防注入原理分析以及使用PDO的注意事項總結》要點:
本文介紹了PHP學習:PDO防注入原理分析以及使用PDO的注意事項總結,希望對您有用。如果有疑問,可以聯系我們。
PHP實戰本文詳細講述了PDO防注入原理分析以及使用PDO的注意事項,分享給大家供大家參考.具體分析如下:
PHP實戰我們都知道,只要合理正確使用PDO,可以基本上防止SQL注入的產生,本文主要回答以下兩個問題:
為什么要使用PDO而不是mysql_connect?
為何PDO能防注入?
使用PDO防注入的時候應該特別注意什么?
?
一、為何要優先使用PDO?
PHP實戰PHP手冊上說得很清楚:
Prepared statements and stored procedures
Many of the more mature databases support the concept of prepared statements. What are they? They can be thought of as a kind of compiled template for the SQL that an application wants to run, that can be customized using variable parameters. Prepared statements offer two major benefits:
PHP實戰The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down an application if there is a need to repeat the same query many times with different parameters. By using a prepared statement the application avoids repeating the analyze/compile/optimize cycle. This means that prepared statements use fewer resources and thus run faster.
?
PHP實戰The parameters to prepared statements don't need to be quoted; the driver automatically handles this. If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
?
即使用PDO的prepare方式,主要是提高相同SQL模板查詢性能、阻止SQL注入
同時,PHP手冊中給出了警告信息
Prior to PHP 5.3.6, this element was silently ignored. The same behaviour can be partly replicated with the PDO::MYSQL_ATTR_INIT_COMMAND driver option, as the following example shows.
Warning
The method in the below example can only be used with character sets that share the same lower 7 bit representation as ASCII, such as ISO-8859-1 and UTF-8. Users using character sets that have different representations (such as UTF-16 or Big5) must use the charset option provided in PHP 5.3.6 and later versions.
?
意思是說,在PHP 5.3.6及以前版本中,并不支持在DSN中的charset定義,而應該使用PDO::MYSQL_ATTR_INIT_COMMAND設置初始SQL, 即我們常用的 set names gbk指令.
?
我看到一些程序,還在嘗試使用addslashes達到防注入的目的,殊不知這樣其實問題更多, 詳情請看
還有一些做法:在執行數據庫查詢前,將SQL中的select, union, ....之類的關鍵詞清理掉.這種做法顯然是非常錯誤的處理方式,如果提交的正文中確實包含 the students's union , 替換后將篡改本來的內容,濫殺無辜,不可取.
?
二、為何PDO能防SQL注入?
請先看以下PHP代碼:
PHP實戰
PHP實戰
PHP實戰看到了嗎?這就是神奇之處,可見這次PHP是將SQL模板和變量是分兩次發送給MySQL的,由MySQL完成變量的轉義處理,既然變量和SQL模板是分兩次發送的,那么就不存在SQL注入的問題了,但需要在DSN中指定charset屬性,如:
PHP實戰知道以上幾點之后,我們就可以總結使用PDO杜絕SQL注入的幾個注意事項:
PHP實戰1.? php升級到5.3.6+,生產環境強烈建議升級到php 5.3.9+ php 5.4+,php 5.3.8存在致命的hash碰撞漏洞.
?
2. 若使用php 5.3.6+, 請在在PDO的DSN中指定charset屬性
PHP實戰3. 如果使用了PHP 5.3.6及以前版本,設置PDO::ATTR_EMULATE_PREPARES參數為false(即由MySQL進行變量處理),php 5.3.6以上版本已經處理了這個問題,無論是使用本地模擬prepare還是調用mysql server的prepare均可.在DSN中指定charset是無效的,同時set names <charset>的執行是必不可少的.
?
4. 如果使用了PHP 5.3.6及以前版本, 因Yii框架默認并未設置ATTR_EMULATE_PREPARES的值,請在數據庫配置文件中指定emulatePrepare的值為false.
?
那么,有個問題,如果在DSN中指定了charset, 是否還需要執行set names <charset>呢?
PHP實戰是的,不能省.set names <charset>其實有兩個作用:
PHP實戰A.? 告訴mysql server, 客戶端(PHP程序)提交給它的編碼是什么
B.? 告訴mysql server, 客戶端需要的結果的編碼是什么
PHP實戰也就是說,如果數據表使用gbk字符集,而PHP程序使用UTF-8編碼,我們在執行查詢前運行set names utf8, 告訴mysql server正確編碼即可,無須在程序中編碼轉換.這樣我們以utf-8編碼提交查詢到mysql server, 得到的結果也會是utf-8編碼.省卻了程序中的轉換編碼問題,不要有疑問,這樣做不會產生亂碼.
?
那么在DSN中指定charset的作用是什么? 只是告訴PDO, 本地驅動轉義時使用指定的字符集(并不是設定mysql server通信字符集),設置mysql server通信字符集,還得使用set names <charset>指令.
?
我真想不通,一些新的項目,為何不使用PDO而使用傳統的mysql_XXX函數庫呢?如果正確使用PDO,可以從根本上杜絕SQL注入,我強烈建議各個公司的技術負責人、一線技術研發人員,要對這個問題引起重視,盡可能使用PDO加快項目進度和平安質量.
?
不要再嘗試自己編寫SQL注入過濾函數庫了(又繁瑣而且很容易產生未知的漏洞).
PHP實戰希望本文所述對大家的PHP程序設計有所贊助.
《PHP學習:PDO防注入原理分析以及使用PDO的注意事項總結》是否對您有啟發,歡迎查看更多與《PHP學習:PDO防注入原理分析以及使用PDO的注意事項總結》相關教程,學精學透。維易PHP學院為您提供精彩教程。