ThinkPHP 3.1中的SQL注入漏洞分析---論ThinkPHP 3.1中的半吊子的PDO封裝

ThinkPHP 3.1中的SQL注入漏洞分析----論ThinkPHP 3.1中的半吊子的PDO封裝 php

 

我總結ThinkPHP的PDO封裝能夠用買櫝還珠來下結論,表面上封裝了PDO支持,但實際卻並無使用到PDO的精髓部分,這不是買櫝還珠是什麼呢? mysql

 

 

花了一些時間瞭解到ThinkPHP 3.1框架,其官方網站上對其描述得至關不錯,但隨着我閱讀其代碼,事實並非想象的那麼好,特別是PDO封裝這一部分,處理得至關糟糕,遠不如使用原生態的PDO安全只是簡單地使用addslashes處理用戶提交的數據,並無使用到PDO的精髓部分:prepare預處理和參數化查詢。這樣帶來的SQL注入的風險更大,建議對安全性要求較高的環境,不要使用addslashes處理用戶提交的內容,若有可能不要使用ThinkPHP框架了,請使用PDO參數化查詢從根本上杜絕SQL注入,或使用安全性處理更好的Yii 框架。 程序員

 

 

首先,分析爲什麼addslashes會在特定條件下形成注入漏洞 sql

請閱讀如下幾個文章,可得知爲什麼變量使用addslashes處理後仍然形成SQL注入, 數據庫

 

PHP字符編碼繞過漏洞--addslashesmysql_real_escape漏洞  安全

http://blog.csdn.net/zhuizhuziwo/article/details/8525789 app

 

 

addslashes:會致使SQL注入漏洞  框架

http://blog.csdn.net/felio/article/details/1226569 less

 

 

 

能夠說,從這點上來看,ThinkPHP框架自吹的水分不少,遠不如想象的那麼好。另外 PHPCMS v9網上暴露的SQL注入漏洞超多,也是由於其依賴addslashes防止SQL注入(結果證實漏洞更多)。 性能

 



 

 

 

 

另外,爲了從根本上防止SQL注入,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: 

 

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. 

 

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). 

 

Prepared statements are so useful that they are the only feature that PDO will emulate for 

drivers that don't support them. This ensures that an application will be able to use 

the same data access paradigm regardless of the capabilities of the database. 

 

 

也就是說,PHP官方強烈推薦使用PDOprepare機制,使用參數化查詢,即SQL查詢模板與變量分離提交,使用bindValue, bindParam的方式處理用戶提交數據,一方面可提高性能,另外一方面可從根本上杜絕SQL注入問題。

 

但很惋惜的是 ThinkPHP仍然使用addslashes方式處理變量,可見其處理方法極其陳舊,充滿SQL注入的風險。

 

事實上,這套框架在此方面處理的至關糟糕。

 

讓咱們追蹤ThinkPHP代碼,找到其處理數據的方式

 

Model::save($data='',$options=array())方法用於保存數據,實際上調用了 $this->db->update($data,$options)

再觀察DbPdo::update()方法,由Db類繼承而來,關鍵點是:$this->parseSet($data)

protected function parseSet($data) {

       foreach ($data as $key=>$val){

            $value   =  $this->parseValue($val);

            if(is_scalar($value)) // 過濾非標量數據

                $set[]    = $this->parseKey($key).'='.$value;

        }

        return ' SET '.implode(',',$set);

    }

 

parseValue方法中,關鍵點是escapeString, DbPdo的方法中:

public function escapeString($str) {

         switch($this->dbType) {

            case 'PGSQL':

            case 'MSSQL':

            case 'SQLSRV':

            case 'MYSQL':

                return addslashes($str);

            case 'IBASE':                

            case 'SQLITE':

            case 'ORACLE':

            case 'OCI':

                return str_ireplace("'", "''", $str);

        }

}

 

即簡單地使用addslashes處理輸入變量。

 

我以爲ThinkPHP中雖然提供了PDO的支持,但實際上仍是使用了addslashes方式處理變量,絲毫沒有使用到PDO的精髓部分, prepare預處理SQL, bindValue, bindParam綁定輸入變量。

 

我認爲這只是自欺欺人的作法,表面上聲稱支持PDO,但徹底是金玉其外,敗絮其中。 能夠哄騙一些小白程序員而已,並不到達到其標稱的安全性目標。

 

若是您使用了ThinkPHP框架,我只能認爲你至關的不幸,並默默爲你祈禱你的站點沒有受到SQL注入攻擊了。

 

那麼,如何處理這個問題倒是留給咱們的重大問題,若是你的項目使用了ThinkPHP,這時候修改框架或是換框架是至關不現實的,那麼只能從擴展ThinkPHP的數據庫訪問層類入手,對其進行處理了。

 

處理辦法以下:

重寫ThinkPHP的數據庫訪問層

1. 在項目目錄 lib中新創建文件DbPdoMysql.class.php 在其中定義DbPdoMysql類,並實際crud的四大方法, 如:

class DbPdoMysql extends DbPdo {    

    public function delete($sql, array $params = array() ) {

        

    }

    

    public function update(array $data, array $options=array(), array $params=array()){

        

    }

    

    public function insert($data,$options=array(),$replace=false, array $params=array() ) {

        

    }

    

    public function select($options=array(), array $params=array() ) {

        

    }

}

 

 

而後,具體使用PDO做參數化查詢的處理,請查閱PHP手冊和ThinkPHP框架的數據庫處理流程。

 

而後,再創建新類,繼承自Moble,並重寫其四大CRUD處理,大體以下:

 

class DbPdoMysql extends DbPdo {

    

    public function delete($conditions='', array $params = array() ) {

        

    }

    

    public function update(array $data, $conditions='', array $params=array()){

        

    }

    

    public function insert(array $data,$options=array(),$replace=false) {

        

    }

    

    public function select($options=array(), array $params=array() ) {

        

    }

}

 

而後,咱們在使用模型進行數據庫操做時,須要特殊處理一下,不能使用舊的方式處理數據庫,以避免形成更嚴重的SQL注入問題。

 

查詢數據時:

$model -> select('where id = ? And name =?', array($_GET['id'], $_GET['name']) )

 

刪除數據時:

$model->delete('where id = ?',  array($_GET['id']))

 

插入數據時使用之前代碼便可(DbPdoMysql類中應該完成參數化處理

 

 

強烈建議您根據本文提供的思路,對使用ThinkPHP的項目進行安全處理,以避免形成潛在的安全隱患。

 

另外,關於PDO的防注入原理分析及使用注意事項,請參閱個人文章

 

PDO防注入原理分析以及使用PDO的注意事項

http://zhangxugg-163-com.iteye.com/blog/1835721

相關文章
相關標籤/搜索