php安全程式設計—sql注入攻擊

傑克.陳發表於2014-12-30
原文:php安全程式設計—sql注入攻擊

php安全程式設計——sql注入攻擊

定義

  1. SQL隱碼攻擊指的是通過構建特殊的輸入作為引數傳入Web應用程式,而這些輸入大都是SQL語法裡的一些組合,通過執行SQL語句進而執行攻擊者所要的操作,其主要原因是程式沒有細緻地過濾使用者輸入的資料,致使非法資料侵入系統。
  2. 根據相關技術原理,SQL隱碼攻擊可以分為平臺層注入和程式碼層注入。前者由不安全的資料庫配置或資料庫平臺的漏洞所致;後者主要是由於程式設計師對輸入未進行細緻地過濾,從而執行了非法的資料查詢。基於此,SQL隱碼攻擊的產生原因通常表現在以下幾方面:

    • 不當的型別處理;
    • 不安全的資料庫配置;
    • 不合理的查詢集處理;
    • 不當的錯誤處理;
    • 轉義字元處理不合適;
    • 多個提交處理不當。
  3. 在某些表單中,使用者輸入的內容直接用來構造動態sql命令,或者作為儲存過程的輸入引數,這些表單特別容易受到sql注入的攻擊。而許多網站程式在編寫時,沒有對使用者輸入的合法性進行判斷或者程式中本身的變數處理不當,使應用程式存在安全隱患。這樣,使用者就可以提交一段資料庫查詢的程式碼,根據程式返回的結果,獲得一些敏感的資訊或者控制整個伺服器,於是sql注入就發生了

常用技術

  1. 強制產生錯誤
    對資料庫型別、版本等資訊進行識別是此型別攻擊的動機所在。它的目的是收集資料庫的型別、結構等資訊為其他型別的攻擊做準備,可謂是攻擊的一個預備步驟。利用應用程式伺服器返回的預設錯誤資訊而取得漏洞資訊。
  2. 採用非主流通道技術
    除HTTP響應外,能通過通道獲取資料,然而,通道大都依賴與資料庫支援的功能而存在,所以這項技術不完全適用於所有的資料庫平臺。SQL隱碼攻擊的非主流通道主要有E-mail、DNS以及資料庫連線,基本思想為:先對SQL查詢打包,然後藉助非主流通道將資訊反饋至攻擊者。
  3. 使用特殊的字元
    不同的SQL資料庫有許多不同是特殊字元和變數,通過某些配置不安全或過濾不細緻的應用系統能夠取得某些有用的資訊,從而對進一步攻擊提供方向。
  4. 使用條件語句
    此方式具體可分為基於內容、基於時間、基於錯誤三種形式。一般在經過常規訪問後加上條件語句,根據資訊反饋來判定被攻擊的目標
  5. 利用儲存過程
    通過某些標準儲存過程,資料庫廠商對資料庫的功能進行擴充套件的同時,系統也可與進行互動。部分儲存過程可以讓使用者自行定義。通過其他型別的攻擊收集到資料庫的型別、結構等資訊後,便能夠建構執行儲存過程的命令。這種攻擊型別往往能達到遠端命令執行、特權擴張、拒絕服務的目的。
  6. 避開輸入過濾技術
    雖然對於通常的編碼都可利用某些過濾技術進行SQL隱碼攻擊防範,但是鑑於此種情況下也有許多方法避開過濾,一般可達到此目的的技術手段包括SQL註釋和動態查詢的使用,利用截斷,URL編碼與空位元組的使用,大小寫變種的使用以及巢狀剝離後的表示式等等。藉助於此些手段,輸入構思後的查詢可以避開輸入過濾,從而攻擊者能獲得想要的查詢結果。
  7. 推斷技術
    能夠明確資料庫模式、提取資料以及識別可注入引數。此種方式的攻擊通過網站對使用者輸入的反饋資訊,對可注入引數、資料庫模式推斷,這種攻擊構造的查詢執行後獲得的答案只有真、假兩種。基於推斷的注入方式主要分為時間測定注入與盲注入兩種。前者是在注入語句里加入語句諸如“waitfor 100”,按照此查詢結果出現的時間對注入能否成功和資料值範圍的推導進行判定;後者主要是“and l=l”、“and l=2”兩種經典注入方法。這些方式均是對一些間接關聯且能取得回應的問題進行提問,進而通過響應資訊推斷出想要資訊,然後進行攻擊

防範方法

  1. 強制字元格式(型別)

    • 對於整形變數, 運用 intval函式將資料轉換成整數
    • 浮點型引數:運用 floatval或doubleval函式分別轉換單精度和雙精度浮點型引數
    • 字元型引數:運用 addslashes函式來將單引號“’”轉換成“’”,雙引號“””轉換成“””,反斜槓“”轉換成“”,NULL字元加上反斜槓“”如果是字元型,先判斷magic_quotes_gpc是否為On,當不為On的時候運用 addslashes轉義特殊字元
  2. 生產環境關閉資料庫錯誤提示,以避免攻擊者得到資料庫的相關資訊。
  3. SQL語句中包含變數加引號
    SELECT * FROM article WHERE articleid=`$id`
    沒有把變數放進單引號中,那我們所提交的一切,只要包含空格,那空格後的變數都會作為SQL語句執行,給了攻擊者構造特殊sql語句的可能。因此,我們要養成給SQL語句中變數加引號的習慣
  4. 使用pdo 使用 prepared statements ( 預處理語句 )和引數化的查詢。這些SQL語句被髮送到資料庫伺服器,它的引數全都會被單獨解析。使用這種方式,攻擊者想注入惡意的SQL是不可能的

    • 使用PDO訪問MySQL資料庫時,真正的real prepared statements 預設情況下是不使用的。為了解決這個問題,你必須禁用 prepared statements的模擬效果。下面是使用PDO建立連結的例子:

      <?php  
      $dbh = new PDO(`mysql:dbname=mydb;host=127.0.0.1;charset=utf8`, `root`, `pass`);  
      $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);  
      ?>  

      這可以確保SQL語句和相應的值在傳遞到mysql伺服器之前是不會被PHP解析的(禁止了所有可能的惡意SQL隱碼攻擊)

    完整示例程式碼:

        <?php  
        $dbh = new PDO("mysql:host=localhost; dbname=mydb", "root", "pass");  
        $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的模擬效果  
        $dbh->exec("set names `utf8`");   
        $sql="select * from table where username = ? and password = ?";  
        $query = $dbh->prepare($sql);   
        $exeres = $query->execute(array($username, $pass));   
        if ($exeres) {   
            while ($row = $query->fetch(PDO::FETCH_ASSOC)) {  
                print_r($row);  
            }  
        }  
        $dbh = null;  
        ?>  

    當呼叫 prepare() 時,查詢語句已經傳送給了資料庫伺服器,此時只有佔位符 ? 傳送過去,沒有使用者提交的資料;當呼叫到 execute()時,使用者提交過來的值才會傳送給資料庫,它們是分開傳送的,兩者獨立的,SQL攻擊者沒有一點機會。

  5. 如下幾種情況,pdo prepared statements 將不能起到防範的作用

    • PDO::ATTR_EMULATE_PREPARES 啟用或禁用預處理語句的模擬。 有些驅動不支援或有限度地支援本地預處理。使用此設定強制PDO總是模擬預處理語句(如果為 TRUE ),或試著使用本地預處理語句(如果為 FALSE)。如果驅動不能成功預處理當前查詢,它將總是回到模擬預處理語句上。
    • 不能讓佔位符 ? 代替一組值,這樣只會獲取到這組資料的第一個值,
      select * from table where userid in ( ? );
      如果要用in來查詢,可以改用find_in_set()實現:
      $ids = `1,2,3,4,5,6`; select * from table where find_in_set(userid, ?);
    • 不能讓佔位符代替資料表名或列名,如:
      select * from table order by ?;
    • 不能讓佔位符 ? 代替任何其他SQL語法,如:
      select extract( ? from addtime) as mytime from table;


相關文章