在没有采取适当预防措施的情况下将用户输入集成到 SQL 查询中时,会出现 SQL 注入的代码漏洞。考虑以下易受攻击的代码片段:
$unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
此场景可以通过用户输入字符串(例如值')来利用; DROP TABLE 表;--,导致恶意查询:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
为了避免此类攻击,必须将数据与 SQL 分离,确保数据被视为数据并且不被 SQL 解析器解释为命令。带有参数化查询的预准备语句提供了强大的解决方案,将 SQL 语句和参数值分开。数据库服务器解析并编译SQL语句,将参数视为字符串,有效阻止恶意SQL注入尝试。
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute([ 'name' => $name ]); foreach ($stmt as $row) { // Do something with $row }
$result = $db->execute_query('SELECT * FROM employees WHERE name = ?', [$name]); while ($row = $result->fetch_assoc()) { // Do something with $row }
$stmt = $db->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // Do something with $row }
默认情况下,PDO 使用模拟准备语句。要禁用 MySQL 模拟并强制执行真正的预准备语句,请设置:
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
类似地,设置:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // error reporting $dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test'); $dbConnection->set_charset('utf8mb4'); // charset
准备好的语句在执行时由数据库服务器解析和编译。参数通知数据库引擎在何处应用过滤器。当执行带有值的预准备语句时,编译后的语句将与这些值组合,而不是与 SQL 字符串组合。这可以防止注入可能导致意外 SQL 执行的恶意字符串。
准备好的语句不适合查询结构发生更改的动态查询。在这种情况下,应使用限制可能值的白名单过滤器。
以上是PHP 中的预处理语句如何防止 SQL 注入?的详细内容。更多信息请关注PHP中文网其他相关文章!