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 部分”的问题?

4

6 回答 6

6

让我们来看看:

请不要mysql_*在新代码中使用函数。它们不再被维护并被正式弃用。看到红框了吗?改为了解准备好的语句,并使用PDOMySQLi -本文将帮助您决定使用哪个。如果您选择 PDO,这里有一个很好的教程

对于初学者。

其次,您正在转义$loginemail,但使用未转义的版本(而不是$loginmail_sql)。

第三,您的代码暗示您将密码按原样存储在数据库中。你不应该。如果攻击者掌握了数据库,您的密码就会被泄露。您应该散列密码并将散列存储在那里。

于 2013-03-20T19:58:02.847 回答
2

是的,您$loginemail在查询中使用的是未更改的。改为使用$loginemail_sql

如需进一步阅读,请查看如何防止 PHP 中的 SQL 注入?

于 2013-03-20T19:56:55.517 回答
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);
于 2013-03-20T20:20:50.200 回答
1

一方面,您要转义 $loginemail,然后在查询中使用未转义的版本。

如果可能的话,您可能要考虑的一件事是使用 PDO 和准备好的语句来简化转义和参数替换。

于 2013-03-20T19:56:55.537 回答
1

您使用 mysql_real_escape_string on$loginemail到达$loginemail_sql,但随后您停止在查询中使用它:

$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1';
于 2013-03-20T19:57:01.470 回答
1

我不是 sql 注入方面的专家,但转义字符串是一个很好的第一步,这应该足够了,尽管可能还有更多工作可以做。

我对您的代码的最大问题是您似乎将密码存储在数据库中的计划文本中。您应该使用盐渍哈希来存储它们。查看此内容以获取更多信息: PHP 密码的安全哈希和盐

你在这段代码中也犯了一个错误:

$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';
于 2013-03-20T19:57:13.953 回答