在 Web 安全领域,SQL 注入(SQL Injection)始终是 OWASP Top 10 中的常客。尽管其原理早已为人熟知,但在实际开发中,由于疏忽或缺乏安全意识,这类漏洞仍然频繁出现。本文将通过一个完整的实战案例,详细记录从发现、复现到修复 SQL 注入漏洞的全过程,并顺带讨论 XSS、CSRF 等常见 Web 安全风险的协同加固思路。
一、环境准备与漏洞发现
假设我们有一个简单的 PHP + MySQL 博客系统,其中有一个通过 id 参数查询文章详情的接口:
http://localhost/blog/article.php?id=1
在代码审计过程中,我们注意到 article.php 中存在如下代码:
$id = $_GET['id'];
$sql = "SELECT * FROM articles WHERE id = $id";
$result = mysqli_query($conn, $sql);
这里直接将用户输入的 id 拼接到 SQL 语句中,没有经过任何过滤或参数化处理,典型的 SQL 注入漏洞。
二、漏洞复现
1. 判断注入点
首先,我们尝试构造 id=1',观察页面返回。如果页面报出 SQL 语法错误,说明单引号被带入数据库执行,存在注入。
http://localhost/blog/article.php?id=1'
返回错误:You have an error in your SQL syntax...,确认注入点存在。
2. 确定字段数
使用 ORDER BY 判断当前查询返回的列数:
http://localhost/blog/article.php?id=1 ORDER BY 5--+
当 ORDER BY 5 时页面正常,ORDER BY 6 时报错,说明查询结果共有 5 列。
3. 联合查询获取数据
接下来,我们利用 UNION SELECT 获取数据库信息:
http://localhost/blog/article.php?id=-1 UNION SELECT 1,version(),database(),user(),5--+
页面回显了数据库版本、当前数据库名和用户信息。继续构造语句,可以获取所有表名:
http://localhost/blog/article.php?id=-1 UNION SELECT 1,group_concat(table_name),3,4,5 FROM information_schema.tables WHERE table_schema=database()--+
进一步获取 users 表中的字段和敏感数据:
http://localhost/blog/article.php?id=-1 UNION SELECT 1,group_concat(username,0x3a,password),3,4,5 FROM users--+
至此,攻击者已可完全读取数据库中的敏感信息,包括管理员账号和密码哈希。
4. 进阶利用
如果数据库权限足够,攻击者还可以通过 INTO OUTFILE 写入 WebShell,或者利用时间盲注、布尔盲注等方式在无回显场景下获取数据。SQL 注入的危害远不止读取数据,还可能导致服务器被完全控制。
三、漏洞修复
修复 SQL 注入的核心原则是:永远不要信任用户输入,并让数据与指令分离。具体措施如下:
1. 使用预处理语句(参数化查询)
这是最有效、最根本的修复方式。将上述代码改为:
$id = $_GET['id'];
$stmt = $conn->prepare("SELECT * FROM articles WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
使用 bind_param 将 id 强制绑定为整型,即使输入包含恶意字符,也只会被当作数据而非 SQL 指令执行。
2. 输入验证与类型转换
对于明确为整型的参数,可以直接进行类型转换:
$id = intval($_GET['id']);
这可以作为辅助手段,但不能替代参数化查询。
3. 最小权限原则
数据库账户应遵循最小权限原则。Web 应用连接数据库的账号不应拥有 FILE、DROP 等高级权限,更不应使用 root 账户。这样即使发生注入,攻击者能造成的破坏也有限。
4. 错误信息处理
关闭生产环境中的详细错误回显,避免将 SQL 错误信息直接暴露给用户。可以通过日志记录错误,但前端只显示统一的提示信息。
5. 部署 WAF
作为纵深防御的一部分,可以在 Web 应用防火墙(WAF)中配置 SQL 注入规则,拦截常见的注入攻击 payload。但 WAF 只是辅助,不能替代代码层面的修复。
四、关联安全风险与整体加固
在修复 SQL 注入的同时,我们也应关注其他常见的 Web 安全风险,形成整体加固方案。
1. XSS(跨站脚本攻击)
如果文章内容直接输出到 HTML 页面而未转义,攻击者可能注入恶意脚本。修复方式是对输出进行 HTML 实体编码:
echo htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
同时,可以设置 Content-Security-Policy 响应头,限制脚本来源。
2. CSRF(跨站请求伪造)
对于修改、删除等敏感操作,应使用 POST 请求,并添加 CSRF Token 校验。Token 应随机生成、一次有效,并与用户会话绑定。
3. 安全加固清单
- 所有数据库查询使用预处理语句;
- 所有用户输入进行验证和过滤;
- 所有输出进行转义;
- 使用 HTTPS 传输数据;
- 设置安全的 Cookie 属性(HttpOnly、Secure、SameSite);
- 定期更新框架和依赖库;
- 建立安全开发生命周期(SDL),在编码阶段即引入安全评审。
五、总结
SQL 注入漏洞的复现过程并不复杂,但其危害却十分严重。通过本次完整的复现与修复,我们可以清晰地看到:一个看似简单的字符串拼接,就可能导致整个数据库沦陷。修复的核心在于使用参数化查询,并辅以输入验证、最小权限、错误处理等多层防御。同时,Web 安全是一个整体,SQL 注入、XSS、CSRF 等风险往往相互关联,只有在开发、测试、运维各环节都贯彻安全思维,才能真正构建起稳固的防线。
未经允许不得转载:任鹏个人博客 » 一次 SQL 注入漏洞的完整复现与修复过程


朋友圈点赞图在线生成源码