一、实验目的
- 理解 SQL 注入漏洞的形成原因与危害。
- 能够从 PHP 源代码中识别 SQL 注入风险点。
- 能够对登录场景和查询场景进行基本漏洞检测。
- 掌握使用预处理语句修复 SQL 注入漏洞的方法。
- 理解输入校验、参数绑定与输出编码的区别。
- 建立基本的安全开发意识与代码审计思维。
二、实验要求
- 部署并运行靶场系统;
- 阅读并分析网站源代码;
- 找出存在 SQL 注入风险的代码位置;
- 对漏洞进行检测与验证;
- 使用安全编码方式修复漏洞;
- 验证修复前后的差异并撰写实验报告。
三、实验步骤及结果
一)靶场部署
请记录靶场部署步骤,包括数据库导入、配置文件修改、网站访问等内容,分别保存截图。
数据库是否导入成功?


首页是否可访问?

登录页是否可访问?

商品查询页是否可访问?

二)漏洞检测
1. 源代码审计与漏洞识别
请阅读 login.php 和 product.php,分析其中是否存在 SQL 注入风险。
2. 对漏洞版靶场进行测试,并记录系统表现。
(1)登录功能检测
请分别使用正常输入、错误输入、测试型特殊输入,分别保存测试结果截图,并进行结果分析。
① 正常输入

- 正常输入测试
- 测试输入:用户名admin,密码admin123
- 测试结果 :页面提示登录成功,成功进入系统
- 结果分析:符合数据库中存储的合法账号密码,SQL 语句正常执行并匹配到用户数据,业务逻辑正常。
② 错误输入

- 错误输入测试
- 测试输入:用户名ad,密码12345
- 测试结果 :页面提示用户名或密码错误,登录失败
- 结果分析:输入与数据库中用户信息不匹配,SQL 查询返回 0 行结果,系统正常拒绝登录。
③ 特殊性输入

- 测试型特殊输入(SQL 注入测试)
- 测试输入:用户名admin'#,密码任意(留空 / 随意输入)
- 测试结果 :页面提示登录成功,绕过密码验证登录
- 结果分析 :代码直接拼接用户输入到 SQL 语句,单引号'闭合 SQL 语句,#注释后续密码验证条件,形成万能密码,成功利用字符型 SQL 注入漏洞绕过登录验证。
(2)商品查询功能检测
请分别测试:合法商品 ID、不存在的商品 ID、异常格式输入或测试型特殊输入。**分别保存测试结果截图,**并进行结果分析 。
- 合法商品 ID

- 合法商品 ID 测试
-
测试输入:商品 ID1
-
测试结果:正常返回商品信息:ID:1,名称:PHP 基础,描述:适合初学者的 PHP 课程,价格:99.00
-
结果分析:输入为合法数字 ID,SQL 语句正常查询并返回匹配数据,业务功能正常。
-
不存在的商品 ID

- 不存在的商品 ID 测试
-
测试输入 :商品 ID 999(数据库无此 ID)
-
测试结果 :页面提示未找到对应商品
-
结果分析:输入 ID 不在数据库中,SQL 查询返回空结果,系统正常提示无对应商品。
-
测试型特殊输入

- 异常格式 / 测试型特殊输入(SQL 注入测试)
- 测试输入:1 AND 1=2 UNION SELECT null,user(),database()#
- 测试结果 :成功泄露敏感信息,显示描述:root@localhost,价格:sql_in
- 结果分析 :id 参数直接拼接进 SQL 语句,无任何过滤与参数化,攻击者可构造联合查询注入,窃取数据库用户名、库名等敏感数据,存在严重数字型 SQL 注入漏洞。
3. 漏洞修复过程
请说明你对漏洞版代码进行了哪些修改,以及修改原因。
(1)login.php 修复说明
原问题(原代码截图):

问题原因
- 直接拼接用户输入 到 SQL 语句,未做安全处理,存在字符型 SQL 注入。
- 攻击者输入 admin'# 可构造万能密码,绕过登录验证。
- 无参数化、无预处理,用户输入可直接改变 SQL 语义
修复措施(修复后代码截图):

修复原因
- 预处理语句(prepare()):先将固定结构的 SQL 模板发送给数据库预编译,SQL 语法结构完全锁定,用户输入仅作为数据传入,永远无法改变 SQL 执行逻辑,彻底切断注入的可能性。
- 参数绑定(bind_param("ss")):用 ? 作为参数占位符,将用户输入与 SQL 结构彻底分离;"ss" 强制限定两个参数为字符串类型,恶意单引号、注释符等仅会被当作普通数据处理,失去注入能力;
- 数据库自动对参数做安全转义,无需手动处理,避免转义不彻底的风险
(2)product.php 修复说明
原问题(原代码截图):

问题原因
- id 参数直接拼接 进 SQL,存在数字型 SQL 注入。
- 攻击者可构造 UNION 查询,泄露数据库用户、库名、版本等敏感信息。
- 无类型检查、无参数化,完全信任用户输入。
修复措施(修复后代码截图):

修复原因
- 通过 bind_param("i", $id) 将参数强制绑定为 整数类型,即使 is_numeric 被绕过,MySQL 也会自动将传入的值转换为整数,使恶意字符失去注入能力,从根本上杜绝数字型注入。
- 使用 ? 作为参数占位符,实现 SQL 结构与用户数据完全分离,确保用户输入仅作为数据传入,无法改变 SQL 逻辑结构。
4. 修复效果验证
请在修复版中重复测试,分别保存测试结果截图,并记录修复前后的差异。
(1)登录页面
结果:正确输入和错误输入无变化,测试型特殊输入有变化。
①正确输入:admin admin123

②错误输入:ad addd

③特殊性输入

(1)登录功能验证
- 修复前 :输入 admin'# + 任意密码 → 登录成功(漏洞可利用)。
- 修复后 :输入 admin'# + 任意密码 → 提示 " 用户名或密码错误"(注入失效)。
- 正常账号:admin/123456 → 仍可正常登录,业务不受影响。
- **错误账号:**ad/addd→用户或密码错误,不可登录。
(2)商品查询页面
结果:正确输入和错误输入无变化,测试型特殊输入有变化。
- 正确输入

- 错误输入 88

③特殊型输入

(2)商品查询功能验证
- 修复前 :输入 1 AND 1=2 UNION SELECT null,user(),database()# → 成功爆出 root@ localhost、sql_in。
- 修复后 :输入相同注入语句 → 显示 " 未找到对应商品",无敏感信息泄露。
- 正常 ID:输入 1 → 正常显示商品信息,业务正常。
- 错误 ID :输入 88不显示商品信息。
修复前后差异总结
- 注入行为:修复前可绕过登录、脱库;修复后注入完全失效。
- 执行机制:修复前输入拼为指令;修复后输入仅为数据。
- 安全性:修复前高危漏洞;修复后符合安全编码规范。
- 业务影响 :正常功能完全不受影响。