这段代码是反 mysql 注入吗?

Is this code anti mysql injection?

我从一个网站上得到了这个例子。我即将升级我的代码的安全性。如果这种代码足够强大以防止注入,请问您有什么意见?

$sql = sprintf(
    "
    INSERT INTO `members`
    (`id`, `username`, `password`, `first_name`, `last_name`)
    VALUES
    ('', '%s', '%s', '%s', '%s')
    ",
    mysql_real_escape_string($con,$_POST['username']),   // %s #1
    mysql_real_escape_string($con,$_POST['password']),   // %s #2
    mysql_real_escape_string($con,$_POST['first_name']), // %s #3
    mysql_real_escape_string($con,$_POST['last_name'])   // %s #4
);

$con 来自 mysql 连接

不,该代码不够强大,无法防止注入。它有很多问题。首先,自 PHP 5.5.0 以来,mysql_* 函数已被 弃用 始终 使用 mysqli_ 扩展的等效功能。我发现你知道转义字符串很奇怪,但你不知道 hash() your password before inserting it into the table. Never store users' passwords in plain text in your database. You want to use Prepared Statements 是防止 SQL 注入的最有效方法。尝试这样的事情。

$q = "INSERT INTO `members` (`id`, `username`, `password`, `first_name`, `last_name`) VALUES ('', ?, ?, ?, ?)";
$stmt = mysqli_prepare($con, $q);
mysqli_stmt_bind_param($stmt, "ssss", $p_user, $p_pass, $p_first, $p_last);

$p_user = $_POST['username'];
$p_pass = hash("sha256", $_POST['password']);
$p_first = $_POST['first_name'];
$p_last = $_POST['last_name'];

mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);

看,在初始查询字符串中,您想使用 VALUES ('', ?, ?, ?, ?)。问号是参数的占位符,您使用变量对其进行绑定。

Have a look at the PHP.net manual on mysqli::prepare 以了解预准备语句的工作原理。这些事情对于保护您的网站和保护用户信息非常重要。使用准备语句时不需要使用 mysqli_real_escape_string(),因为参数已经转义。

附带说明:当您对密码进行哈希处理时,不要退回到 commonly-used md5(),因为这是非常不安全的,而且按照今天的标准 easily-crackable。使用更安全的算法,例如 sha256.

对于已知 mysql_real_escape_string() 失败的某些情况,您应该阅读 SQL injection that gets around mysql_real_escape_string()

在您显示的具体代码中,假设您也可以控制字符集,那么您应该是安全的。但总的来说,mysql_real_escape_string() 不是 SQL 注入保护的可靠或安全解决方案。

mysql_real_escape_string() 打字也很乏味。因此,一些开发人员在尝试快速完成代码时会跳过安全编码。 “我只是让这段代码先工作,稍后我会添加安全性。坏主意。

虽然查询参数不会失败,而且它们实际上很容易使用,所以一旦养成习惯,人们更有可能从一开始就使用它们来编写安全代码。

@TannerBabcock 提供了mysqli的例子,不过我更喜欢PDO,因为这样更简单:

$sql = "
    INSERT INTO `members`
    (`username`, `password`, `first_name`, `last_name`)
    VALUES (?, ?, ?, ?)
    ",
$params = [
    $_POST['username'],
    password_hash($_POST['password'], PASSWORD_DEFAULT),
    $_POST['first_name'],
    $_POST['last_name']
];
$stmt = $pdo->prepare($sql);
$stmt->execute($params);

在 PDO 中,您可以简单地将参数数组传递给 execute(),我认为这比将可变参数列表传递给 mysqli_stmt_bind_param() 的 mysqli 方法更容易。

PDO 也支持命名参数,而 mysqli 不支持。