我正在研究一个可能被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被错误处理并且可能包含一些dangerouse“SQL部分”的问题?
答案 0 :(得分:6)
让我们看看:
Please, don't use
mysql_*
functions in new code。它们不再被维护and are officially deprecated。请参阅red box?转而了解prepared statements,并使用PDO或MySQLi - this article将帮助您确定哪个。如果您选择PDO here is a good tutorial。
首先。
其次,您正在转义$loginemail
,但使用未转义的版本(而不是$loginmail_sql
)。
第三,您的代码暗示您将密码按原样存储在数据库中。你不应该。如果攻击者掌握了数据库,您的密码就会受到损害。你应该散列密码并在那里存储哈希值。
答案 1 :(得分:2)
是的,您在查询中使用的$loginemail
未更改。请改用$loginemail_sql
。
如需进一步阅读,请查看 How to prevent SQL injection in PHP?
答案 2 :(得分: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);
答案 3 :(得分:1)
首先,您要转发$ loginemail,然后在查询中使用未转义的版本。
如果可能,您可能需要考虑的一件事是使用PDO和预处理语句来简化转义和参数替换。
答案 4 :(得分: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';
答案 5 :(得分:1)
我不是sql注入方面的专家,但是逃避字符串是一个很好的第一步,应该足够了,尽管可能还有更多工作要做。
我的代码最大的问题是您似乎将密码存储在数据库中的计划文本中。您应该使用salted哈希来存储它们。查看此信息以获取更多信息: 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';