2012-07-13 19 views
2

考慮一個項目,將工作一個以上的開發,並且將得到不斷的更新和維護,這兩個代碼是什麼下文可以被認爲是PHP的最佳實踐,考慮可讀性和安全?如果我們在表演中談話,the second option will probably be a little better,但有辦法解決這一點。

選項1

$user = $_POST['user']; 
$pass = $_POST['pass']; 

// Prevent SQL Injection and XSS 
$user = anti_injection($user); 
$pass = anti_injection($pass); 

if(strlen($user) <= 8 && strlen($pass) <= 12) 
{ 
    // SQL query 
    $sql = "SELECT id 
      FROM users 
      WHERE username = '$user' AND password = '$pass';"; 
} 

選項2

// Retrieve POST variables and prevent SQL Injection and XSS 
$_POST['user'] = anti_injection($_POST['user']); 
$_POST['pass'] = anti_injection($_POST['pass']); 

if(strlen($_POST['user']) <= 8 && strlen($_POST['pass']) <= 12) 
{ 
    // SQL query 
    $sql = "SELECT id 
      FROM users 
      WHERE username = '" . $_POST['user']. "' AND password = '" . $_POST['pass'] . "';"; 
} 

編輯1

我不使用MySQL

,我的數據庫是PostgreSQL的

+4

如果您對安全感興趣,爲什麼不使用綁定參數? – andrewsi 2012-07-13 14:46:42

+0

這兩個實際上是一樣的,但看起來很醜,但我是一個瘋狂的編碼器,我抽象和做的東西有點過於邊緣一段時間... – 2012-07-13 14:49:10

+1

我總是會使用第一個選項,如果只是爲了確保我永遠不要忘記在值上調用'anti_injection'。第二個選項不知何故神奇地推斷它正在發生,但你永遠無法確定。另外,我會確定第一個更快,因爲數組訪問速度可能比訪問變量慢 - 您確定性能嗎? – poke 2012-07-13 14:50:17

回答

7

不要這樣做。

我只能假設anti_injection是某種自定義過濾功能,這是一個壞主意™。如果你真的想要採用這些想法,你應該使用mysql_real_escape_string

只有寫入SQL查詢時要保持安全的方法是使用參數,例如,通過MySQLi。無論如何,mysql_*函數正在被棄用,所以你最好儘快移動。

實際上mysql_real_escape_string並不是針對注入攻擊的萬無一失的防禦措施。考慮查詢中的整數比較,如WHERE $var > 30。我可以成功地將1=1 or 100注入$var,並徹底打破邏輯。

參數與查詢語言完全分離數據,完全緩解注入風險。服務器接收到一個包含參數符號和一組要插入的值的查詢,因此它可以完全不同地處理查詢語言和數據。

此外,您似乎以明文存儲密碼。 This isa badidea.您應該研究一種強密碼存儲哈希算法,如bcrypt,這使得從哈希中獲得明文密碼非常困難。

MD5和SHA1對於密碼存儲並不理想,因爲它們設計的速度很快,這意味着攻擊者可以快速破解強大的密碼。現代GPU可以實現每秒50億次MD5哈希。實際上,有些人使用專門的散列裂解設備,其中一些可以在45 billion hashes per second處破解MD5。

你也應該看看這些真棒問題,這完全覆蓋SQL注入攻擊,密碼存儲,以及其他安全問題衆多:

更新:你提到你正在使用postgres。您可以使用PDO來運行來自PHP的參數化查詢,如described briefly here

+1

感謝您的提示,它們將對我非常有用。我會看到你提出的所有問題 – 2012-07-13 15:23:09

3

這些選項都不是最佳做法,只適用於可疑anti_injection,這幾乎可以肯定不能像廣告中那樣工作。還有的事項:

  • 改寫(munging)的手動輸入數據驗證他們
  • 存儲明文密碼
  • 構建SQL查詢,而不是使用綁定參數

根據項目的範圍之前最後一個可能是可以接受的。

關於性能,第一個選項在理論上會更快,因爲它的數組索引更少。但差距肯定會很小,根本不可觀察。第一個選項也更具可讀性,並且提供了更好的抽象,所有這些僅僅是可以忽略不計的額外內存。

2

兩者都是錯誤的。您似乎將密碼存儲爲純文本,這只是爲了解決問題。

此外,如果我的用戶名是"123456",我將無法登錄,因爲您將其轉義爲\"123456\",並且「長度< = 8」檢查失敗。

1

如果你想要安全性和性能,我會建議使用PDO。使用參數時,您不能sql注入。下面是一個例子,你需要爲下面的工作「定義」mysql params。

這也使得數據庫緩存查詢,因爲它不會在每次使用不同的參數,這將提高性能以及執行時間而改變。

:p_user and :p_pass 

用於表示參數和

array (':p_user' => $user, ':p_pass' => $pass ') 

設置參數,你需要傳遞的價值觀。

你也應該考慮增加一個密碼鹽,和存儲SHA1在數據庫中,這樣如果你的數據庫受到攻擊,你的密碼不會被黑客明確地發現。

class users{ 
    function __construct() { 
    define('MySQLHost', 'localhost'); 
    define('MySQLName', 'databasename'); 
    define('MySQLUser', 'username'); 
    define('MySQLPass', 'password'); 
    define('pwsalt', 'tScgpBOoRL7A48TzpBGUgpKINc69B4Ylpvc5Xc6k'); //random characters 
    } 

    static function GetQuery($query, $params) 
    { 
    $db = new PDO('pgsql:host='.MySQLHost.';dbname='.MySQLName.';', MySQLUser, MySQLPass); 
    $cmd = $db->prepare($query); 
    $cmd->execute($params); 

    if($cmd->rowCount()==0) 
     return null; 
    return $cmd->fetchAll(); 
    } 

    static function GetUser($user, $pass) 
    { 
    $query = "select id 
     from `users` 
     where username = :p_user and password = :p_pass"; 

    $rows = users::GetQuery($query, array(
     ':p_user' => $user, 
     ':p_pass' => sha1($pass.pwsalt) //Append the salt to the password, hash it 
    )); 

    return $rows; 
    } 
} 

$user = $_POST['user']; 
$pass = $_POST['pass']; 
if(strlen($user) <= 8 && strlen($pass) <= 12) 
{ 
    $result = users::GetUser($user, $pass); 
    if($result != null) 
    print 'Login Found'; 
} 
+0

不錯的例子,它對我很有用。我將在PHP文檔中閱讀更多詳細信息 – 2012-07-13 15:23:49

+1

PDO是此問題的唯一正確答案。 – 2012-07-13 16:42:00

0

雖然我同意其他海報,但不要試圖「重新發明輪子」關於SQL安全性,這個問題似乎是關於性能和如何使用超全球。作爲最佳實踐,不要改變超全局變量($ _GET,$ _POST,$ _REQUEST,$ _SYSTEM等)。我想不出一個違反此規則會提高性能的示例,並且任何修改將導致不確定性和混亂。

所以在這種情況下,兩個選項都是正確的。 Option1不必要地複製一個變量(根據Google性能文檔,禁止複製)。選項2突變超全球,違反了上述準則。相反,這樣做:

$user = anti_injection($_POST['user']); 
$pass = anti_injection($_POST['pass']); 

if(strlen($user) <= 8 && strlen($pass) <= 12) ... 

不過,我應該重申,「自制衛生」是一個可怕的前景,其他評論者已經制定了相當徹底在這一點上。