2013-03-20 65 views
1

我正在調查一個可以sql注入的項目(一個用戶報告它)。不安全的登錄腳本 - 如何保護

這裏是登錄腳本的一部分:

$loginemail = $_POST['loginemail'];     
      $loginemail_sql = mysql_real_escape_string($loginemail);     

      $password = $_POST['loginpass'];     
      $password_sql = mysql_real_escape_string($password);     

      //get user data 
      $q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1'; 

我想現在如果這部分代碼可能被注入? 是否有$ loginemail和$ password被錯誤處理並可能包含一些危險的「SQL部分」的問題?

+1

'mysql_real_escape_string'已被棄用,你應該散列密碼。 – 2013-03-20 19:56:36

+0

[更多信息](http://www.php.net/manual/en/mysqlinfo.api.choosing.php)對'mysql *'函數的棄用。切換到'mysqli'或PDO。 – ajp15243 2013-03-20 19:59:29

回答

6

讓我們來看看:

Please, don't use mysql_* functions in new code。他們不再維護and are officially deprecated。看到red box?請改爲了解prepared statements,並使用PDOMySQLi - this article將幫助您決定哪個。如果您選擇PDO,here is a good tutorial

對於初學者。

其次,您正在轉義$loginemail,但使用非轉義版本(而不是$loginmail_sql)。

第三,代碼暗示您將密碼原樣存儲在數據庫中。你不應該。如果攻擊者抓住數據庫,你的密碼就會被破壞。您應該散列密碼並將散列存儲在那裏。

1

首先,您正在轉義$ loginemail,但隨後在查詢中使用了非轉義版本。

如果可能,您可能需要考慮的一件事是使用PDO並準備語句以簡化轉義和參數替換。

1

您使用$loginemail mysql_real_escape_string在$loginemail_sql到達,但你突然停止在查詢中使用它:

$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1'; 
1

我m沒有sql注入專家,但逃避字符串是一個很好的第一步,應該是足夠的,儘管可能有更多可以完成。

我的代碼最大的問題是,你似乎將密碼存儲在數據庫的計劃文本中。你應該使用鹽漬散列來存儲它們。檢查了這一點的詳細信息: Secure hash and salt for PHP passwords

另外你在這段代碼犯了一個錯誤:

$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1'; 

應該是:

$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail_sql.'" AND password="'.$password_sql.'" LIMIT 1'; 
2

那麼@Madara Uchiha說停止使用mysql_ *函數是很好的。但他沒有舉出任何例子。所以我會的。對不起,我的英語,我是巴西人:)

PDO:

<?php 
$loginemail = $_POST['loginemail']; 
$password = $_POST['loginpass']; 

// open a PDO connection within mysql driver 
// PDO uses DSN string for connections they look like: "driver:options" 
$dsn = 'mysql:dbname=testdb;host=127.0.0.1'; 
// DB username 
$dbUser = 'dbuser'; 
// DB password 
$dbPassword = 'dbpass'; 
// PDO is instantiable, so you need to create an object for each connection 
$dbh = new PDO($dsn, $dbUser, $dbPassword); 
// You must prepare your query, PDO uses a placeholder system for sanitize data and avoid injection, params can be passed using "?" or ":varname" 
$stmt = $dbh->prepare('SELECT uid, full_name, score, status FROM users WHERE email= :email AND password= :password LIMIT 1'); 
// Binding a param called :email 
$stmt->bindValue(':email', $loginemail); 
// Binding a param called :password 
$stmt->bindValue(':password', $password); 
// Execute the PDOStatement 
$stmt->execute(); 
// Then fetch result 
$result = $stmt->fetchAll(PDO::FETCH_ASSOC); 
// ALSO, you can fetch only one row using 
$firstRow = $stmt->fetch(PDO::FETCH_ASSOC);