sql联合查询注入是利用union操作符将恶意查询结果与合法查询结果合并,从而从数据库中窃取数据的一种攻击手段。在php中防御此类注入的核心做法是彻底禁用数据库连接中的多语句执行功能,并严格使用预处理语句(prepared statements)进行参数化查询,确保用户输入仅被视为数据而非可执行的sql代码。

联合注入的攻击原理是什么
联合注入依赖于数据库支持UNION语法且允许返回多列结果。攻击者通过构造特殊的输入,使应用程序生成的SQL语句包含UNION SELECT子句,进而读取其他表的数据。例如,当应用直接拼接用户输入时,攻击者可以闭合原有查询并追加新的SELECT语句。

$id = $_GET['id']; $sql = "SELECT * FROM products WHERE id = $id"; $result = mysqli_query($conn, $sql);
上述代码中,如果$id被赋值为' UNION SELECT 1, username, password FROM users --',则最终执行的SQL将把用户表中的数据作为产品列表的一部分返回。这种漏洞产生的根本原因是字符串拼接导致的类型混淆,即数据库引擎无法区分哪些部分是结构指令,哪些部分仅仅是文本数据。
立即学习“PHP免费学习笔记(深入)”;
如何使用PDO预处理语句修复
使用PDO扩展的预处理语句可以有效防止联合注入。预处理语句将SQL模板与数据分离,数据库引擎先编译SQL模板,再绑定用户提供的参数。由于参数在编译后才会被插入,因此无论输入内容如何特殊,都不会改变SQL的结构逻辑。

$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM products WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);
$product = $stmt->fetch();
在这个示例中,:id是一个占位符。即使$_GET['id']包含恶意的UNION语句,它也会被PDO视为一个普通的字符串值传递给数据库,数据库在执行时会将其与id字段进行精确匹配,而不是解析为SQL关键字。这种方法不仅解决了联合注入,还能抵御大多数基于SQL语法的注入攻击。
MySQLi多语句执行带来的风险是什么
除了联合注入,PHP开发者还需警惕MySQLi扩展默认允许的多语句执行特性。如果未显式关闭该功能,攻击者可能在单个请求中发送多个SQL语句,导致数据泄露或破坏。这通常发生在处理复杂业务逻辑时,开发者误以为需要一次性执行多条命令。
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$mysqli->multi_query("SELECT * FROM products; DROP TABLE users");
上述代码展示了multi_query方法的潜在危险。如果用户输入被直接拼接到第一个查询中,或者整个查询字符串由用户控制,攻击者可以在末尾追加DROP TABLE等破坏性命令。为了防止这种情况,应始终使用单语句查询方法如query()或prepare(),并在初始化连接后调用real_escape_string()对输入进行转义,尽管预处理仍是更优选择。



















