Sql注入基础知识补全
这篇文章是 SQL 注入入门实验记录 的配套基础补全。 如果你在看那篇实验记录的时候,对"地址栏里那串东西到底是什么","+ 和 -- 到底干嘛用的"感到困惑,就从这里开始读起吧
我总结了以下几个阶段,可以结合自己自身的情况,选择性的学习
使用的示例坏境是Linux虚拟机+Docker部署本地靶场这一篇博客里,我所示例搭建的pikachu靶场,本篇用pikachu靶场介绍数字型和字符型注入,实验记录那篇用的是另一个靶场,原理是一样的
pikachu靶场帮助手册:点我下载 密码:hqne
第一阶段:数据库到底是什么?
你可以把数据库想象成一个Excel工作簿

Pikachu里的用户数据大概长这样
表名:users
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 123456 |
| 2 | test | abc123 |
+----+----------+----------+一个正常的SQL查询是这样执行的:
SELECT username, password FROM users WHERE id = 1;翻译成人话就是:"从users表里,找id等于1的那行,把username和password给我"
第二阶段:注入的根源——为什么字符串拼接很危险?
现在来看Pikachu后台PHP代码大概是怎么写的(简化版):
$id = $_POST['id']; // 从前端表单取值,比如用户选了 "1"
$sql = "SELECT * FROM users WHERE id = " . $id;
// 拼接结果:"SELECT * FROM users WHERE id = 1"这看起来没问题对吧?
但是往往问题就出现在这里,如果用户不老实,输入的不是 1,而是 1 or 1=1:
$sql = "SELECT * FROM users WHERE id = " . "1 or 1=1";
// 拼接结果:"SELECT * FROM users WHERE id = 1 or 1=1"这句SQL的含义变成了:"找id=1的,或者……1=1(永远为真)的数据"
结果:把整张表的数据都返回了
原理解释:
因为 1=1 永远为真,导致 WHERE 条件对每一行都成立,
而数据库会对每一行判断:
- 不管这一行的
id是多少 1=1都是 truetrue OR anything = true
✔ 所以每一行都满足条件
✔ 最终返回整张表
第三阶段:注入点判断——先"试探"(确立数据库的“控制权”)
打开我们装的pikachu靶场,和burp suite工具(如果你还没有安装burp suit,那我建议去看看这个文章:点我直达burp suit安装指南)
以下的讲解,我会结合burp suite来进行

打开Repeater模块(注意下图的红框部分)

现在我们来"试探"这个输入框,把这里的id=1后面的数字1,改成2,3,4,然后点击左上角的send按键,看看左侧发生了什么(*注:需要在右侧的Respone下面的几个选项中,选择Render,才能和我一样,看到预览效果)

主要观察我这里的预览效果中的这个红框,看看有啥不同之处(如上图id=2和下图id=3的区别)

很明显,id=2和id=3所输出的显示都不一样了
这就说明了一个问题,那就是这里的id=number被后端的数据库给带入进去查询了
居然知道了这一点,那我们接下来测试:1 and 1=1,带入进去看看有结果

天真的你,输入后发现,为啥我的这个显示报错?按道理来说,不因该返回正常的结果吗?
这里你就漏掉了一个很关键的点,你漏掉了“空格”!
1 and 1=1,是1“我是空格”and“我也是空格”1=1
*注:burp suite会把”空格“当成分隔符,所以为了代替正常的“空格”输入,我们需要使用“+”来进行连接,所以正确的语句是下图所示

这样左侧就有数据了
可是光输入这1 and 1=1,我们还是不能准确的分辨出后面输出的语句是否被数据库执行了,所以我们输入一个假数据,来炸一下数据库,看看会返回什么结果

这次数据库返回给了我们一个查询不到的结果,那这就更加能够说明我们刚刚的and后面的语句被数据库执行了
这时候的数据库在干啥?
当我们发送这个1+and+1=2请求时,数据库执行的指令变成了:
“请把用户 ID 等于 1,并且 1 等于 2 的数据找出来给我”请想象以下的后端数据库语句的这个场景:
(1)先从前端那里拿到了用户的数据,数据库一看,id=1 是真的,但 1=2 永远是假的(在 AND 逻辑中,只要有一个是假的,整个条件就是假)
(2)数据库在表里搜了一圈,发现没有哪条记录能满足“1等于2”这个荒唐的条件,于是它两手一空,什么也没查到
(3)因为数据库没给后端数据,后端代码就走到了“未找到结果”的逻辑分支,给你吐出了“不存在”的提示
第四阶段:理解数据库背后的操作(核心原理部分)
这个实验的意义在于确立了我们对于数据库的“控制权”,通过对比 1=1(有数据)和 1=2(没数据),证明了一个极其重要的事实:
我们刚刚输入的逻辑指令,被数据库老老实实地执行了
如果数据库没有漏洞(即开发者做了防护),我们输入的 and 1=2 会被当成一段纯文本。数据库会去寻找一个 id 真的叫做 "1 and 1=2" 的用户。显然,由于 ID 是数字,它应该报错或者直接找不到,而不是去执行那个 1=2 的逻辑运算
(此处可能也是执行也是这个纯文本的线路,最终输出的也是这个“找不到数据的结果”,但是由于我们是初学者,所以就暂时先排除这种可能存在的情况)换句话来说,括号内的说的情况确实可能发生,但是前期看不懂不理解,可以先忽略
结论: 只要页面结果会根据你输入的 1=1 和 1=2 的真假而反复横跳,就铁证如山地证明了数据库在执行你的逻辑,而不是把它当成死板的文字
既然页面会随着你输入的 逻辑真假 而发生 显示变化,这就确认了这是一个标准的 布尔型反馈,也是注入成功的铁证
这个操作其实是在验证:
我们能不能控制数据库的“判断逻辑”
一旦成立,我们就可以:
- 一位一位猜密码(盲注)
- 一字符一字符爆数据
布尔盲注的本质:通过控制条件真假,观察页面变化,从而间接获取数据
那我们现在再回到数据库的视角,看看数据库在干嘛
SELECT * FROM users WHERE 条件它只做一件事:
判断“条件是真是假”
而经过刚刚我们的操作,现在能做到:
- 让它变真 ✅
1 and 1=1 - 让它变假 ❌
1 and 1=2
这就叫:我们控制了判断逻辑
第五阶段:字符型注入
不过,先别急着去爆数据
你有没有注意到,我们刚才一直在测试的是 id=1?它的参数值是一个纯数字
正因为是纯数字,我们往后面直接加 and 1=1,数据库才老老实实地把它当逻辑条件执行了
但……如果这个参数值不是数字,而是一个单词、名字、或者一串文字呢?
那就完全是另一回事了——这就引出了我们下一个要学的概念:字符型注入
在上一阶段,我们搞清楚了数字型注入的原理:参数值是数字,后台SQL大概长这样:
SELECT * FROM users WHERE id = 1我们输入 多输入一个and 1=1,SQL就变成:
SELECT * FROM users WHERE id = 1 and 1=1但是,现实里很多参数并不是数字,而是文字——比如用户名、搜索关键词、文章标题。后台SQL大概是这样写的:
SELECT * FROM users WHERE username = 'admin'注意到区别了吗?参数值 admin 被单引号包裹着
Q:为什么单引号这么重要?
A:你可以把单引号理解成SQL语言里的"文字标签"
数据库看到单引号就知道:“哦,单引号里面的是文字内容,不是指令,我要原样去数据库里查找这个文字”
那如果用户输入的是 admin' and 1=1,SQL就变成:
SELECT * FROM users WHERE username = 'admin' and 1=1'等等,最后多出来了一个落单的单引号'这句SQL直接语法错误,什么都不会执行。
所以字符型注入的核心难题就是:你得先把前面那个单引号"关掉",才能让后面的逻辑指令被执行
字符型注入的"万能公式"
我们需要做两件事:
- 闭合前面那个开着的单引号
- 注释掉SQL语句里原本在后面的内容(不然会多出来乱七八糟的东西导致报错)
所以字符型注入的基础语句长这样:
' and 1=1 --+拆开来解释:
| 片段 | 作用 |
|---|---|
' | 闭合前面后端代码里开着的那个单引号 |
and 1=1 | 我们想注入的逻辑判断条件 |
-- | 注释符,告诉数据库:我后面的内容都不算,全部忽略 |
+ | burp suite中的拼接,前面我们也提到了,仅仅用于拼接语句的作用 |
注释符的原理:
-- 是SQL里的行注释符,它后面的所有内容数据库都不会去读。+ 在URL里代表空格,因为 -- 后面必须接一个空格才能生效(有些地方直接写 -- - 或者 # 也可以,后面我们会遇到)
接下来我们使用Pikachu靶场来感受一下
第一步:先输入一个单引号,"撬开"一条裂缝
在用户名输入框里,输入一个单引号(%27也可以,这个是单引号的URL编码,是同一个意思):
'可以看到,页面返回了报错的信息

这个报错翻译就是:"你的SQL语法有错误"
这正好验证了我们刚才讲的那个结论:
输入单引号 → 页面报错 → 说明单引号打破了SQL语句的结构 → 这里是字符型注入
那么此时此刻,数据库那边执行了什么?
SELECT * FROM users WHERE username = '''是的,这里有3个引号,数据库肯定报错了(后端的流程如下)
后台原本的SQL: WHERE username = ' $name '
↑ ↑
开头引号 结尾引号
你输入了一个 ',代入进去变成:
WHERE username = ' ' '
↑ ↑ ↑
开头 你的 结尾
引号 单引号 引号现在引号的配对情况是:
- 第一个
'和第二个'配对了 → 变成了一个空字符串 - 第三个
'落单了,没有人和它配对 → SQL语法直接崩掉
数据库看到这句话就懵了——这句SQL不完整,没法执行,于是直接抛出了我们看到的那个报错:
You have an error in your SQL syntax...
步骤二:把这个'换成以下的这个式子,看看会发生什么
'+or+'1发现居然打印出了全部的数据

我们输入的这些信息被数据库执行了
为什么会输入全部的结果,那我们来看后端SQL长什么样
我们输入的 '+or+'1 代入进去之后,变成:
SELECT * FROM users WHERE username = ''+or+'1'数据库判断每一行的时候,逻辑是这样的:
username = '' → 假(没有用户名为空的)
or '1' → 真(字符串 '1' 非空,在SQL里等同于 true)
假 OR 真 = 真所以每一行都满足条件,整张表都被返回了
跟我们之前用的 and 1=1 对比一下

or 比 and 更"危险",因为只要有一个条件为真,整个条件就成立。而 '1' 作为一个非空字符串,在MySQL里永远是真值,效果等同于 1=1
第六阶段:URL参数解析
现在你已经理解了数字型注入和字符型注入的基本原理。但你有没有发现,我们在实验记录里操作的时候,注入语句并不是直接打进输入框的,而是写在了地址栏里?
那地址栏里那串
?id=1+and+1=1到底是什么格式?+真的是加号吗??是干嘛用的?这一阶段我们就来把这些东西说清楚
我们输入在地址栏里的那串东西,到底是什么?
在之前的实验记录里,我们在地址栏输入了这样一条 URL:
192.168.153.139/search.php?id=1+and+1=1串东西是什么格式?? 后面是什么?+ 是加号吗?下面我把这条 URL 拆开逐段解释
URL 的基本结构
一条完整的 URL 由以下几部分组成:
| 片段 | 名称 | 作用 |
|---|---|---|
192.168.153.139 | 主机地址 | 告诉浏览器去找哪台服务器 |
/search.php | 路径 | 这里是我这个服务器IP下的某个文件地址 |
? | 查询字符串起始符 | 分隔路径和参数,固定写法,它后面的才是传给程序的数据(可以理解成只是一个分隔符) |
id=1 | 参数键值对 | id 是参数名,1 是参数值,服务器会读取这个值去数据库查询 |
所以,在地址栏看到的:
id=1+and+1=1实际上发给服务器、再传进 SQL 语句的是:
id=1 and 1=1*注意:除了 +,还有另一种写法是 %20(空格的十六进制 ASCII 编码)这两种写法等价。在某些场景下 + 会失效,这时候就要改用 %20
写在末尾
到这里,Sql基础知识的部分就告一段落了
我们从"数据库是什么"开始,一路走到了字符型注入的原理、URL参数的格式——这些都是理解注入攻击的地基
如果你觉得自己已经准备好了,可以去看配套的实验记录,看看这些原理在真实靶场里是怎么一步一步被用起来的:
👉 SQL 注入入门 —— 从暴力破解到 Union 注入(实验记录)
实验记录里用的是整数型注入和数据库语句的查询,这两个我们在基础补全里已经铺垫过了,如果读的过程中哪个地方又懵了,随时可以翻回这里对照着看

