在mysqli中预防SQL注入

21 浏览
0 Comments

在mysqli中预防SQL注入

我之前对mysqli非常陌生,之前都是用mysql编写查询语句,但mysqli更先进,所以这是我第一次使用它。以下是我的PHP代码。

function clean($str) {
    $str = @trim($str);
    if(get_magic_quotes_gpc()) {
        $str = stripslashes($str);
    }
    return mysql_real_escape_string($str);
}
$email = clean($_POST['email']);
$password = clean($_POST['password']);
if(empty($res['errors'])) {
    $result = $mysqli->query("SELECT uid FROM users where email='$email' and password = '$password'");
    if($result->num_rows == 1){
        $res['success'] = true;
    }
    else{
        array_push($res['errors'], '无效的登录详细信息');
        $res['success'] = false;
    }
}else{
    $res['success'] = false;        
}
echo json_encode($res);
}

clean函数的工作不如预期,因为如果我输入用户名和密码正确,sql查询会返回false。所以在mysqli中似乎是无效的。我查看了这个链接PHP MySQLI Prevent SQL Injection,得知我们需要准备查询。我看到有一个示例,但我不知道如何准备/绑定如果我要使用两个或更多的表单数据。感谢您的时间。

更新后的代码

$result = $mysqli->prepare("SELECT uid FROM users where email=:email and password = :password");
$result->execute([
    ':email' => $email,
    ':password' => $password
]);
if($result->num_rows == 1){
    $res['success'] = true;
}
else{
    array_push($res['errors'], '无效的登录详细信息');
    $res['success'] = false;
}

0
0 Comments

防止SQL注入的原因是由于在数据库查询操作中,没有对用户输入的参数进行正确的过滤和处理,导致恶意用户可以通过在输入中插入SQL语句来执行恶意操作,如删除数据库、修改数据等。为了解决这个问题,可以使用mysqli的bind_param()函数来绑定参数,并指定参数的类型。

下面是一个示例代码,展示了如何使用bind_param()函数来防止SQL注入:

$stmt = $mysqli->prepare("SELECT uid FROM users where email= ? and password = ?");
$stmt->bind_param('ss', $email, $password);
/* 执行预处理语句 */
$stmt->execute();

在上述代码中,使用prepare()函数将SQL语句进行预处理,然后使用bind_param()函数来绑定参数。'ss'表示参数的类型为字符串,$email和$password是用户输入的变量。通过这种方式,用户输入的参数会被正确地转义和处理,从而防止SQL注入攻击。

除了字符串类型的参数,还可以使用其他类型的变量。下面是一些可用的参数类型:

- i:整数类型

- d:浮点数类型

- s:字符串类型

- b:二进制数据类型

通过使用bind_param()函数,可以确保用户输入的参数在执行数据库查询操作时得到正确的处理,从而防止SQL注入攻击。

0
0 Comments

在这段对话中,出现了一个关于如何防止SQL注入的问题。问题的原因是使用了错误的函数(mysql_real_escape_string)和语法(直接在查询语句中插入变量),导致代码容易受到SQL注入攻击。解决方法是使用预处理语句(prepared statement)来绑定变量,从而避免了SQL注入的风险。

在原始代码中,使用了以下语句进行查询:

$result = $mysqli->query("SELECT uid FROM users where email='$email' and password = '$password'");

这段代码容易受到SQL注入攻击,因为直接将变量插入到查询语句中。

解决方法是使用预处理语句来绑定变量。以下是修改后的代码示例:

<?php
$stmt = $dbConnection->prepare("SELECT uid FROM users where email = :email AND password = :password");
try{
$stmt->execute([
    ':email' => $email,
    ':password' => $password
]);
}
catch(Exception $e){
    echo $e->getMessage(); //发布时删除
}
if($stmt->num_rows){
    $res['success'] = true;
}
?>

这段代码使用了预处理语句来绑定变量。首先,使用prepare函数创建一个查询模板,其中用占位符(:email和:password)代替了变量。然后,使用execute函数执行查询,将变量与占位符进行绑定。这样可以确保输入的变量不会被当做SQL代码执行,从而防止了SQL注入攻击。

在对话中,还提到了使用mysql_real_escape_string函数和clean函数来防止SQL注入攻击的方法。然而,这些方法并不推荐使用,因为它们可能存在漏洞,而且不如预处理语句安全和方便。

最后,对话中还提到了使用PDO替代MySQLi的建议。因为PDO支持更多的驱动程序,所以更加灵活和强大。

0
0 Comments

随着评论中已经提到的,你需要在API的选择上保持一致。在这里,你开始使用了mysqli_*,所以我会继续使用它。你的代码中有一些mysql_*和PDO,使用PDO可能是一个不错的选择,但是如果你的服务器支持mysqli_*,使用它也没有问题。参考并自行决定(只需避免使用mysql_*,它已经过时了)。

使用mysqli_*来连接数据库(你没有展示你的连接):

$mysqli = new mysqli("host", "username", "password", "database");
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: (".$mysqli->connect_errno.") ".$mysqli->connect_error;
}
$mysqli->set_charset("utf8");

至于防止SQL注入,你只需要使用预处理语句。如果有某些值你不希望出现在表中,你仍然可以对数据进行“清理”或“净化”处理,但这是另一个讨论的话题。

你还需要知道数据库中的密码是否经过哈希处理。它们确实应该经过哈希处理,如果你使用的是PHP5.5及以上版本,应该使用`password_hash($password, $algorithm)`和`password_verify($password, $hash)`(如果不是,请使用类似`password_compat`的工具)。

你的哈希处理也需要保持一致,不能使用md5进行插入,然后在查询时不使用哈希。它们必须保持一致。因为如果你选择使用md5哈希进行查询,并将其与未经哈希处理的字符串进行比较,它们将不同,查询将失败。

下面是一个使用`password_verify()`的示例,这意味着存储在数据库中的密码也需要使用`password_hash()`进行存储(否则查询将失败)。

if ($stmt = $mysqli->prepare("SELECT uid, password FROM users where email=?")) {
    $stmt->bind_param("s", $_POST['email']);           // 绑定变量到占位符
    $stmt->execute();                                 // 执行查询
    $stmt->bind_result($userID, $password);         // 将选定的列设置为变量
    $stmt->fetch();                                   // ...并获取它
    if ($stmt->num_rows) {
        if (password_verify($_POST['password'], $password)) {
            // 密码正确且与邮箱匹配!
        } else {
            // 密码错误...
        }
    } else {
        // 账户名不存在
    } 
}

这只是一个基本示例,但它可以帮助你入门。永远不要相信用户的输入,使用预处理语句。

0