SQL注入是Web安全里最常见也最危险的漏洞之一,攻击者通过拼接恶意SQL片段篡改查询逻辑,能绕过登录、拖库甚至拿到服务器权限。要从根本上防护,需要理解注入产生的原理并在编码层面落地几条核心规则。

为什么会出现SQL注入
当程序把用户输入直接拼接到SQL字符串里执行,就给了攻击者控制语句结构的机会。比如下面这段PHP代码就有明显问题:
<?php $name = $_GET['name']; $sql = "SELECT * FROM user WHERE name = '$name'"; // 如果传入 name = ' OR '1'='1,条件永远成立 ?>
使用预编译语句阻断拼接
预编译语句(Prepared Statement)让SQL结构和参数分开传输,数据库先解析语句模板,再把参数当作纯数据处理,从机制上杜绝注入。
Java中使用PreparedStatement
import java.sql.*;
public class SafeQuery {
public static void main(String[] args) throws Exception {
String sql = "SELECT id, name FROM user WHERE name = ?";
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/test", "root", "pass");
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "张三"); // 参数绑定,不会被当成SQL代码
ResultSet rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("name"));
}
}
}
PHP中使用PDO
<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=test", "root", "pass");
$stmt = $pdo->prepare("SELECT * FROM user WHERE name = :name");
$stmt->execute(['name' => $_GET['name']]);
$rows = $stmt->fetchAll();
?>
输入校验与白名单
即便用了预编译,对输入做类型与格式校验仍是好习惯。比如分页参数必须是正整数,排序字段只能从固定列表里选。
- 用正则限制手机号、邮箱格式
- 枚举值走白名单,不要直接把字段名拼进ORDER BY
- 对长度做上限截断
最小权限与纵深防御
数据库账号不要给root权限,按业务拆账号只授权需要的表和列。同时配合Web防火墙和ORM框架进一步降低风险。
| 措施 | 作用 |
|---|---|
| 预编译语句 | 从语法层隔离参数与指令 |
| 输入校验 | 减少异常数据进入系统 |
| 最小权限 | 被攻破时损失可控 |
ORM就能高枕无忧吗
像MyBatis、Hibernate确实默认用参数绑定,但如果写SQL片段时用${}而不是#{},依然会引入拼接注入。开发时要清楚框架里哪些写法安全、哪些会裸拼。
安全不是某个工具能包办的事,而是写每一行数据库代码时的习惯。
小结
提升SQL注入防护实战能力,核心是放弃字符串拼接查询、全面使用预编译、做好输入限制并收紧数据库权限。把这些动作变成编码规范,系统的抗攻击能力会明显增强。