2013-12-21 24 views
3

我正在從擴展mysql轉換到PDO,並在閱讀所有我可以從你和其他地方的大師,我有一些剩餘的疑慮。我想出了以下內容來解決典型查詢的sql注入問題。我只是想知道這是否足夠,或者可能是我在白名單上有些過度,然後再將其複製到我的所有應用程序中。PDO /準備聲明/白名單/設置字符集,是否足夠安全以防止注入

我不清楚我是否正確地使用了白名單,也就是說,如果我也應該以某種方式逃脫。

此外,我不知道是否應該將屬性設置爲false爲每個查詢或只爲腳本一次。

$link = new PDO("mysql:host=$hostname;dbname=$database;charset=utf8", $username, $password); 

$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 

      $arr_i=$arr_k=''; 
      $m_act=$v_act='Y'; 
      $table = array('prices', 'versions', 'models'); 
      $allowedTables = array('prices', 'versions', 'models');    
      $field = array('model_id', 'version_id', 'price', 'models.active', 'versions.active'); 
      $allowedFields = array('model_id', 'version_id', 'price', 'models.active', 'versions.active'); 
      if(count(array_diff($field, $allowedFields))==0 AND count(array_diff($table, $allowedTables))==0){ 
      $sql = "SELECT COUNT(DISTINCT `" . $field[0] . "`) as ctmod FROM `" . $table[0] . "` 
      INNER JOIN `" . $table[1] . "` USING (`" . $field[1] . "`) 
      INNER JOIN `" . $table[2] . "` USING (`" . $field[0] . "`) 
      WHERE `" . $field[2] . "` BETWEEN :arr_i AND :arr_k 
      AND " . $field[3] . " = :m_act 
      AND " . $field[4] . " = :v_act"; 
      $stmt = $link->prepare($sql); 
      $stmt->bindParam(':arr_i', $arr_i, PDO::PARAM_INT); 
      $stmt->bindParam(':arr_k', $arr_k, PDO::PARAM_INT); 
      $stmt->bindParam(':m_act', $m_act, PDO::PARAM_STR); 
      $stmt->bindParam(':v_act', $v_act, PDO::PARAM_STR); 
      for ($i=0; $i < $ctpri; $i++){ 
      $k=$i+1; 
      $arr_i=$arr_pri[$i]+1; 
      $arr_k=$arr_pri[$k]; 
      $stmt->execute(); 
      while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) { 
      $ctmod[] = $r['ctmod']; 
      } 
      } 
      } 
      else{die();} 
+1

http://codereview.stackexchange.com/ – Mihai

+0

所有這些亂七八糟的問題是什麼?爲什麼你不能直接在查詢中寫一個提交的名字? –

回答

3

是的,你的代碼是完全安全的SQL注入。做得好。

儘管@YourCommonSense指出,在您顯示的例子中,沒有理由將表和列名稱變爲變量。將它們直接寫入查詢會更簡單。

因此,我假設你問這個問題,因爲你有有時通過應用程序邏輯或變量選擇表和列的名稱,即使你沒有在這個特定的例子中顯示它。


我會提供的唯一祕訣是:

  • 所有字符串連接,結尾雙引號,使用.並重新開始雙引號使代碼看起來凌亂,它可以要弄清楚你開始和停止了哪些雙引號。 PHP字符串插值的變量另一種風格在大括號包圍,如下所示:

    $sql = "SELECT COUNT(DISTINCT `{$field[0]}`) as ctmod FROM `{$table[0]}` 
        INNER JOIN `{$table[1]}` USING (`{$field[1]}`) 
        INNER JOIN `{$table[2]}` USING (`{$field[0]}`) 
        WHERE `{$field[2]}` BETWEEN :arr_i AND :arr_k 
        AND `{$field[3]}` = :m_act 
        AND `{$field[4]}` = :v_act"; 
    
  • 而對於另一種選擇,你可以在這裏使用的文件,所以你不必擔心劃定在所有的字符串。不錯,如果你有你的字符串字母雙引號,因爲你沒有逃脫他們:

    $sql = <<<GO 
        SELECT COUNT(DISTINCT `{$field[0]}`) as ctmod FROM `{$table[0]}` 
        INNER JOIN `{$table[1]}` USING (`{$field[1]}`) 
        INNER JOIN `{$table[2]}` USING (`{$field[0]}`) 
        WHERE `{$field[2]}` BETWEEN :arr_i AND :arr_k 
        AND `{$field[3]}` = :m_act 
        AND `{$field[4]}` = :v_act 
    GO; 
    
  • 最後,它無關SQL注入,但一個好的做法是檢查返回值爲prepare()和​​,因爲如果在解析或執行過程中發生錯誤,它們會返回false

    if (($stmt = $link->prepare($sql)) === false) { 
        trigger_error(PDO::errorInfo()[2], E_USER_ERROR); 
    } 
    

    (這個例子使用PHP 5.4語法取消引用從函數返回數組)。

    ;否則可以configure PDO to throw exceptions,所以您不必檢查。

    $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    
+0

謝謝,我現在感覺好多了。幾點意見:你需要去掉AND子句的後面的引號。出於某種原因,可能是因爲字符串有一個點(models.active),我認爲它不適用於它們。我很感激你向我展示了錯誤處理的方式,我還有很多需要學習的東西。其中之一是我會在哪裏找到PDO/PHP拋出的異常/錯誤。 – BernardA

+0

@BernardA,你應該分別爲表名和列名劃分:'\'models \'。\'active \''。儘管分隔這些並不是必要的,因爲它們不是[MySQL保留字](http://dev.mysql.com/doc/refman/5.6/en/reserved-words.html),也不包含特殊字符或空格。 –

+0

謝謝。沒關係。當我想到這一點時,閱讀這樣的查詢是相當混亂的。在數組中使用鍵可能更好,並使用表/字段的名稱。 – BernardA

4

我懷疑你確實要有點過分與白名單。不僅在白名單上,甚至在準備好的陳述中也是如此。爲了滿足你錯誤的觀點,你過度設計你的查詢,以至於完全不可理解的混亂。

你需要了解的是,任何恆定值是安全的設計。所以,使用或者使用白名單和準備聲明絕對沒有意義。

所以,與其

AND " . $field[3] . " = :m_act 

你應該寫只是

AND versions.active = 'Y' 

沒有任何結合或白名單。

所有你需要保護的只是動態值。所以,你只需要爲$ arr_i和$ arr_k使用預處理語句。所有其他查詢部分都必須直接寫入查詢中,就像您之前做的一樣。

+1

@YCS,如果我知道一切都是正確的,我不會問這個問題開始。我感謝你的意見,但肯定不是它的基調。如果您打算保持相同的語氣,如果您今後不回答我的任何問題,我將不勝感激。我學習的事實並不意味着我會接受被欺負。 – BernardA

+4

我不知道你在說什麼「口氣」。我沒有提到你的技能或知識或任何其他個人特徵。我所做的只是回答你的問題,提供唯一可靠的答案。所以,請遏制你的想象力。 –

+2

@YCS,這正是問題所在。我看到你的發言。你經常這樣做,沒有被拒絕,你認爲它是可以的。呃,事實並非如此。如果你願意進一步討論這個問題,我建議你在我的個人資料郵件中寫信給我。我討厭用這個打擾其他SO夥伴。 – BernardA