PHP / MySQLi:如何防止 SQL INSERT 注入(代码部分工作)

PHP / MySQLi: How to prevent SQL injection on INSERT (code partially working)

我想使用 PHP 在 MySQL 数据库中存储两个值(电子邮件和密码)。输入通过 jQuery 中的 Ajax 传递到 PHP 页面(通过网站上的 onclick 事件)。

现在 我想保护这个 PHP 查询免受 SQL 注入 - 我说的是标准网站,所以我不想做得太过分它,但我认为一些标准的保护不会坏。

以下是我之前所做的,只是为了确保一般程序正常运行。 然后我尝试通过使用 密码加密 语句 来提高安全性,但我不确定我这样做是否正确 + 我不知道这是否以及如何也需要应用于 Select 部分(我正在检查电子邮件是否已经存在)。

我看过很多关于这个主题的页面,但作为初学者,这正是我的问题所在。 有人可以以此为例说明应该在此处更改或添加什么,并可能提供一些简短的解释吗?如果可能,我想继续使用 MySQLi

旧PHP:

$conn = new mysqli($servername, $username, $password, $dbname);
$conn->set_charset("utf8");
if($conn->connect_error){
    die("Connection failed: " . $conn->connect_error);
}
$email = $_POST["email"];
$pw = $_POST["pw"]; 

$sql = "SELECT email FROM Users WHERE email = '" . $email . "'";
$query = $conn->query($sql);
if(mysqli_num_rows($query) > 0){
    echo "Record already exists";
}else{
    $sql = "INSERT INTO Users (email, pw) VALUES ('" . $email . "', '" . $pw . "')";
    if($conn->query($sql)){
        echo "Update successful";
    }else{
        echo "Update failed";
    };
}
$conn->close();

新 PHP:

$conn = new mysqli($servername, $username, $password, $dbname);
$conn->set_charset("utf8");
if($conn->connect_error){
    die("Connection failed: " . $conn->connect_error);
}
$email = $_POST["email"];
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 

$sql = "SELECT email FROM Users WHERE email = '" . $email . "'";
$query = $conn->query($sql);
if(mysqli_num_rows($query) > 0){
    echo "Record already exists";
}else{
    $sql = $conn->prepare("INSERT INTO Users (email, pw) VALUES ('" . $email . "', '" . $pw . "')");
    $sql->bind_param('s', $name);
    $sql->execute();
    $result = $sql->get_result();
    if($result){
        echo "Update successful";
    }else{
        echo "Update failed";
    };
}
$conn->close();

新 PHP 代码 片段中,您仍然容易受到注入攻击。
您在插入部分使用了准备好的语句,但实际上并没有正确使用准备工作的强度。

创建准备好的语句时,您创建了一个查询,您在其中添加了占位符而不是原始值:

$stmt = $conn->prepare("INSERT INTO Users (email, pw) VALUES (?, ?)");

问号是占位符,稍后使用bind_param方法替换:

$stmt->bind_param('ss', $email, $pw);

绑定调用的 ss 部分告诉 mysql 数据库它的两个字符串被传递到数据库(s for string, i 对于 int 等).
您正在绑定一个参数 ($name) 但它在查询中没有占位符或任何类型的引用..?

另一方面,您的 select 声明仍然不安全并且存在漏洞。
我可能会在那里使用准备好的语句,就像插入部分一样。

你总是想确保用户的输入对数据库来说是"safe",如果你连接一个查询字符串并将用户输入添加到其中,数据库将不会转义字符串,它只会运行它。

仅在您自己编写完整查询时使用标准 query 方法调用,没有任何输入参数,尤其是没有用户传递的输入参数!

$query = $mysqli->prepare("INSERT INTO `table` (`col1`, `col2`) VALUES (?, ?)");
$col1 = 100;
$col2 = 14;
$query->bind_param('ii', $col1, $col2);
$query->execute();
$query->close();