2013-03-20 33 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);