
本文介绍在本地搭建的php测试环境中,通过构造特定输入来演示sql注入原理,帮助开发者理解未过滤用户输入的风险,并强调仅限授权环境使用。
本文介绍在本地搭建的php测试环境中,通过构造特定输入来演示sql注入原理,帮助开发者理解未过滤用户输入的风险,并强调仅限授权环境使用。
SQL注入是一种经典且危害严重的Web安全漏洞,其根源在于将用户输入直接拼接到SQL查询语句中,未做任何转义或参数化处理。本文以您提供的PHP登录代码为例,说明如何在完全可控、合法授权的测试环境(如本地XAMPP/LAMP)中安全复现该漏洞,目的在于提升安全意识与防御能力——切勿在未经授权的系统上尝试。
漏洞成因分析
您的登录逻辑存在两个关键缺陷:
- 未过滤用户输入:$_POST['user'] 直接拼入SQL语句;
- 业务逻辑错误:密码比对在PHP层进行($row['password'] == $_POST['pass']),而非由数据库验证,导致攻击者可绕过密码校验。
原始查询为:
SELECT username,password FROM utenti WHERE username='[用户输入]';
当输入 ' UNION ALL SELECT username, '' FROM utenti WHERE '' = ' 时,完整SQL变为:
SELECT username,password FROM utenti WHERE username='' UNION ALL SELECT username, '' FROM utenti WHERE '' = '';
由于 '' = '' 恒为真,第二条SELECT会返回表中所有用户名,且password字段被强制设为空字符串('')。此时PHP遍历结果集,只要提交任意空密码($_POST['pass'] = ''),即可满足 $row['password'] == $_POST['pass'] 条件,成功绕过认证。
安全修复方案(必须实施)
✅ 立即改用预处理语句(推荐):
$stmt = $link->prepare("SELECT username, password FROM utenti WHERE username = ?");
$stmt->bind_param("s", $_POST['user']);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
if (password_verify($_POST['pass'], $row['password'])) { // 假设密码已hash存储
// 登录成功
}
}✅ 补充措施:
- 对密码字段使用password_hash()加密存储,禁止明文保存;
- 移除错误信息中的敏感细节(如具体SQL语句),防止信息泄露;
- 启用mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)捕获异常;
- 使用最小权限数据库账户(避免root连接生产库)。
⚠️ 重要提醒:本文所有示例仅适用于您本人拥有完全控制权的本地测试环境。在真实系统中实施SQL注入属于违法行为,违反《网络安全法》及各国计算机犯罪相关法律。安全研究必须遵循“授权、边界、留痕”三原则。
掌握漏洞原理是为了更好地构建防线。请始终将输入验证、参数化查询和最小权限原则作为开发默认实践。

















