在这里和其他地方,我读过几篇文章说,如果首先将用户输入的每个字符串(以及在数据库查询中使用的字符串)首先放入mysqli_real_escape_string(),则使用mysqli_set_charset()可以防止SQL注入。
但是,没有什么比准备好的语句更安全了。不是其中任何一个的专家,代码中的这些行是真的吗?
$input = "This is an input string";
mysqli_set_charset($conn, 'utf8');
$input = mysqli_real_escape_string($conn, $input);
足以防止SQL注入吗?当然,我假设实际上每个输入都被转义了。就我目前的理解而言,应该是这样,但是我怀疑我目前的理解是否足够。我知道在某些情况下mysqli_real_escape_string()可能会失败,但这些情况似乎取决于脆弱的字符集(根据我目前的理解)。
答案 0 :(得分:2)
这里的关键是永远不要使用mysqli_real_escape_string
,除非您有充分的理由。组成一个简单的查询不是一个。
mysqli_real_escape_string
可以防止SQL注入。具有占位符值 的预备语句将防止SQL注入。这是一个重要的区别。
考虑以下代码:
$a = $_POST['a'];
$b = $_POST['b'];
$c = $_POST['c'];
$d = $_POST['d'];
// ...
$a = $conn->real_escape_string($a);
$a = $conn->real_escape_string($b);
$c = $conn->real_escape_string($c);
$d = $conn->real_escape_string($d);
$conn->query("INSERT INTO x (a,b,c,d) VALUES ('$a', '$b', '$c', '$d')");
由于一个小错误,它中有一个SQL注入错误。微小的错误并不重要,即使是这样的单个漏洞也足以完全破坏您的应用程序。
相反,使用带占位符值的预准备语句:
$stmt = $conn->prepare('INSERT INTO x (a,b,c,d) VALUES (?,?,?,?)');
$stmt->bind_param('ssss', $_POST['a'], $_POST['b'], $_POST['c'], $_POST['d']);
$stmt->execute();
即使在此处输入错误,也可能发生的最糟糕情况是查询失败或插入错误的数据。您没有SQL注入错误。您的应用程序不会受到威胁。我什至建议您在定义查询时使用单引号,这样您就永远不会尝试使用变量插值(这是一种注入形式)。
还值得注意的是,bind_param
方法的代码更少,并且可读性更高。真的没有理由对这种情况使用手动转义。