PHP+MySQL SQL 注入攻防实战:从漏洞利用到双层安全防护
前言
SQL 注入是 Web 安全领域最经典、危害最高的高危漏洞,也是渗透测试、安全实训的核心考点。很多中小企业 PHP 网站因开发不规范,直接拼接用户输入到 SQL 语句,导致数据库账号、密码、用户隐私全部泄露,严重时会被恶意删库。 本文基于 PHP+MySQL 登录靶场完整实操笔记,完整讲解从基础万能密码绕过、高阶 UNION 手动脱库、BP+SQLmap 自动化批量渗透,再到代码根治、数据库兜底的全套防御方案,兼顾原理、实操与企业落地规范。
一、基础漏洞:单引号字符型注入 —— 万能密码免密登录
1. 漏洞产生根源
靶场登录页面login.php存在原生安全缺陷:接收username、password表单参数后,没有做转义、过滤、正则校验,直接把用户输入拼接进 SQL 查询语句。 后端固定 SQL 模板为:
SELECT * FROM users WHERE username='用户输入' AND password='密码输入';
单引号是字符串闭合标识,攻击者可以利用单引号提前截断原有 SQL 结构,篡改查询逻辑,形成字符型注入漏洞。
2. 万能密码攻击原理与 Payload
标准万能密码:' or 1=1# 拼接后恶意 SQL 语句:
SELECT * FROM users WHERE username='' or 1=1 #' AND password='123456';
逐段拆解攻击逻辑:
':闭合程序自带的单引号,切断原有账号匹配逻辑;or 1=1:逻辑或 + 恒真条件,只要满足其一就返回数据,破除账号密码双重校验;#:MySQL 单行注释符,把后面AND password='xxx'密码校验代码全部屏蔽失效。
输入该 Payload,任意填写密码,就能直接绕过登录验证。 如果网站做了空格过滤,可使用无空格绕过 Payload:admin 'or'1'='1。
3. MySQL 三种注释符区分
#:单行注释,兼容性最好,无需空格,实训首选;--:单行注释,横线后必须带空格,否则注释失效;/* */:多行注释,适合复杂 SQL 语句、多冗余代码场景。
二、高阶渗透:UNION 联合查询注入,手动脱库拿全量数据
万能密码仅能绕过登录,想要批量窃取数据库所有表、账号、邮箱,需要使用 UNION 联合查询注入,该手法有三个硬性前置条件,缺一不可:
- 前后两条 SELECT 查询的字段数量完全一致;
- 对应位置字段数据类型兼容(文本对文本、数字对数字);
- 页面存在数据回显位,能展示 SQL 查询结果。
标准化五步攻击流程
- 判断注入点:用户名输入单引号
',页面抛出数据库语法报错,说明参数存在字符型注入; - Order By 探测字段数:使用
1' order by 数字#逐步测试,本靶场users表共 5 个字段,输入1' order by 5#页面正常,1' order by 6#直接报错,确定字段总数; - 构造联合查询语句:使用
union select拼接查询语句,查询数据库名、表名、字段; - 利用页面回显输出敏感数据;
- 遍历读取全表用户明文账号密码。
实操中可借助 Burp Suite 拦截、修改 POST 请求参数,反复调试注入语句,实现手动脱库。
三、实战工具链:BurpSuite+SQLmap 全自动一键脱库
手动注入步骤繁琐、容易出错,真实渗透场景都会使用工具组合自动化打穿漏洞,两大工具分工明确:
- BurpSuite:中间人抓包工具,拦截浏览器与服务端的登录 POST 数据包,导出完整请求样本;
- SQLmap:专业自动化注入工具,自动识别注入点、爆库、爆表、批量导出所有敏感数据。
完整实操步骤
- 开启 BP 拦截(Intercept On),浏览器配置代理
127.0.0.1:8080,访问登录页面提交表单,拦截 POST 请求; - 将拦截到的完整请求复制,保存为
login.txt文本文件; - 解决虚拟机网络问题:Windows 本地 PHPStudy 网站地址为
127.0.0.1,虚拟机 Kali 无法访问,需要查看 VMnet8 虚拟网卡 IP,修改数据包内 Host 地址; - Kali 终端执行 SQLmap 全套脱库指令:
# 自动检测漏洞,无需人工交互
sqlmap -r login.txt --batch
# 查询服务器全部数据库
sqlmap -r login.txt --dbs --batch
# 查询指定web_login库下的数据表
sqlmap -r login.txt -D web_login --tables --batch
# 查询users表所有字段名与字段类型
sqlmap -r login.txt -D web_login -T users --columns --batch
# 一键导出users表全部用户数据(脱库)
sqlmap -r login.txt -D web_login -T users --dump --batch
执行完成后,数据库内所有用户名、明文密码、邮箱都会自动导出保存。
四、根源防御:PHP mysqli 预处理参数化查询
以上所有注入手段,都可以通过参数化预处理查询彻底根治,也是企业开发标准规范,唯一能从底层杜绝 SQL 注入的方案。
防御核心原理
将 SQL 语法结构与用户输入数据完全隔离,使用?作为固定占位符,SQL 语句结构提前锁定,用户提交的所有内容只会被数据库识别为普通字符串,无法闭合单引号、篡改 SQL 逻辑,彻底切断注入通道。
完整安全代码
<?php
header("Content-Type:text/html;charset=utf-8");
// 连接数据库
$host = "数据库ip";
$user = "用户";
$pwd = "密码";
$dbname = "数据库名";
$conn = mysqli_connect($host, $user, $pwd, $dbname);
if (!$conn) die("连接失败:" . mysqli_connect_error());
// 获取前端账号密码
$username = $_POST['username'];
$password = $_POST['password'];
// 预处理固定SQL结构,使用?占位符
$sql = "SELECT * FROM users WHERE username=? AND password=?";
$stmt = mysqli_prepare($conn, $sql);
// ss代表两个参数均为字符串类型
mysqli_stmt_bind_param($stmt, "ss", $username, $password);
// 执行查询
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if (mysqli_num_rows($result) > 0) {
echo "登录成功!欢迎:" . $username;
} else {
echo "登录失败!用户名或密码错误";
}
mysqli_close($conn);
?>
防护生效效果
部署预处理代码后,所有注入攻击全部失效:
- 万能密码 Payload 提交只会提示账号密码错误;
- Order By 探测字段数无报错,无法判断注入点;
- SQLmap 清空缓存重新扫描,无法识别注入漏洞;
- 不存在任何篡改 SQL 逻辑的可能性。
五、兜底防护:MySQL 最小权限原则
预处理代码是主动防御,但如果代码出现遗漏、更新出错,需要数据库账号权限作为第二道安全防线,限制漏洞爆发后的破坏程度。
防护逻辑
网站禁止使用 root 超级管理员账号连接数据库,root 拥有删库、删表、修改全库的最高权限,一旦注入成功直接全站数据销毁。我们创建业务专用低权限账号,仅开放业务必需操作。
实操 MySQL 权限命令
# 创建仅本地访问的业务账号webuser
CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'web123456';
# 仅授予查询、插入权限,删除、清空、删库等高风险权限全部禁用
GRANT SELECT,INSERT ON web_login.* TO 'webuser'@'localhost';
# 刷新权限生效
FLUSH PRIVILEGES;
权限测试与局限性
使用webuser登录数据库,仅能执行查询、新增用户;执行DROP、TRUNCATE、DELETE等操作会直接提示无权限,避免攻击者删库跑路。 但该方案存在短板:账号拥有 SELECT 查询权限,攻击者依旧可以读取、盗取全部用户数据,只能降低破坏程度,不能阻止数据泄露,仅作为兜底防护。
六、总结:企业双层安全防护闭环
- 漏洞未修复状态:万能密码绕过登录、UNION 手动脱库、Burp+SQLmap 自动化批量脱库全部可成功利用,数据库完全暴露;
- 第一层主动防御(代码层):PHP mysqli 预处理参数化查询,从根源消除 SQL 注入漏洞,是必须落地的核心方案;
- 第二层被动兜底(数据库层):MySQL 账号最小权限分配,限制漏洞造成的破坏,防止删库、销毁业务数据;
- 开发规范总结:所有涉及用户输入拼接 SQL 的场景,统一使用预处理;业务数据库账号严禁使用 root 超级管理员,形成代码 + 数据库双层安全闭环。
更多推荐


所有评论(0)