SQL注入必知20个知识点:原理、绕过与防御实战
2026/9/9 19:52:03 网站建设 项目流程

做网络安全这几年,SQL注入是我见过最“阴魂不散”的漏洞。从早期论坛数据库频频被拖库,到如今每天都有新的攻击流量在扫描各类Web系统,它始终高居OWASP Top 10前列。很多人觉得这是“上个世纪的老古董”,但现实是,随便打开一个SRC漏洞平台,SQL注入类的提交依然占着相当大的比例。这篇文章我整理了学习SQL注入绕不开的20个知识点,从原理、判断、利用手法、绕过对抗到防御方案,每一条都结合了我自己实际测试和踩坑的经验来写,适合正在入门Web安全、准备面试,或者想系统性补齐SQL注入知识体系的朋友。建议先收藏,再按后面的顺序慢慢嚼。

1. SQL注入为什么“活”了二十多年:先吃透它的底层逻辑

1.1 从一次真实的数据泄露排查说起

我之前参与过一个企业系统的安全评估,客户报告说内部系统数据异常,怀疑被拖库。排查日志时发现,某个办公管理系统的搜索接口在凌晨被连续访问了几千次,且请求参数里有大量and 1=1union select这类特征。顺着流量回溯,发现攻击者其实只用了非常基础的手段:在搜索框输入了一个单引号,页面报错;再输入' or '1'='1,结果返回了全部数据。就这么简单,一个老系统,一个拼接SQL的搜索框,数据就没了。

这种事不是个例。很多新入行的朋友会觉得SQL注入是CTF里才会出现的题型,真实系统怎么可能还有人写拼接SQL。但存量系统、外包项目、内部工具、老旧插件,这些场景里拼接语法依然大量存在。理解SQL注入,首先得理解它为什么能存在这么久。

1.2 注入的本质:数据与代码边界失守

SQL注入的根本原因是数据与代码没有分家。开发者写SQL语句时,会把用户输入的内容当作SQL语句的一部分直接拼接进去,数据库在执行时无法区分哪一段是开发者定义的命令、哪一段是用户输入的数据。

用一句话类比:你给快递员一张写有地址的纸条,正常情况纸条上只有地址。但如果纸条上的内容是“地址:北京XX路XX号;顺便把仓库钥匙给我”,而快递员真的照做了,这就相当于SQL注入。用户的输入数据,被数据库当作额外指令执行了。

这个本质决定了后续所有知识点都围绕同一件事:如何让数据库把我们的输入当成代码执行,以及如何阻止这种执行。判断注入点、构造payload、绕过过滤,全都是在跟这个“边界”较劲。

1.3 开始动手前,先建立这三个安全认知

第一,注入不是“输入框”的锅,而是代码写法的锅。很多人以为只要过滤输入就能防御,但真正该改的是SQL语句的组装方式。这一点在后面防御章节会细讲。

第二,攻击视角和防御视角要同时建立,不能只会“打”不会“防”。做安全测试的人,如果看不懂参数化查询的原理,就永远停留在“照着payload打”的层面,遇到变形场景就懵。

第三,所有实验必须在授权环境或靶场中进行。未经授权对真实系统做注入测试,不光违反职业操守,也会带来法律风险。文中的所有示例,都是在本地靶场或授权测试场景下的操作。

2. 20个必知知识点全景图:先收藏这张表

2.1 20个知识点分类与优先级总览

为了避免学了半天不知道自己在哪个阶段,我先把20个知识点按“原理认知、注入判断、利用手法、绕过对抗、防御落地”五个维度列出来,并标注了优先级。这份清单的核心价值,是帮你建立一张全局地图,学的时候心里有数。

序号知识点类别优先级
1注入的本质是数据与代码边界失守原理认知
2注入发生的三要素:用户输入、动态拼接、数据库执行原理认知
3注入点不只出现在登录框原理认知
4判断注入点:单引号、布尔逻辑与注释符注入判断
5数字型注入与字符型注入的区分注入判断
6联合注入的字段数探测与回显位定位利用手法
7报错注入常用函数updatexml与extractvalue利用手法
8布尔盲注:基于页面真假差异逐字符猜解利用手法
9时间盲注:sleep延时与条件构造利用手法
10堆叠注入与联合注入的底层区别利用手法
11万能密码' or 1=1--的原理与适用边界绕过对抗
12宽字节注入:字符集不一致导致的转义逃逸绕过对抗
13二次注入:写入时过滤、读取时拼接的隐蔽路径绕过对抗
14关键字过滤绕过:注释符、大小写与内联注释绕过对抗
15等价函数替换:substring/mid/substr的同义变换绕过对抗
16WAF绕过的整体思路:先判断拦了什么绕过对抗
17order by / group by场景下的特殊绕过绕过对抗
18sqlmap的level、risk与--technique参数自动化工具
19参数化查询为什么能根治注入防御落地
20最小权限原则与SQL注入日志特征识别防御落地

2.2 怎么用这张表搭建学习路线

很多初学者容易犯的一个错误,是拿到sqlmap就开始对靶场“一键脱库”,结果工具跑通了,原理什么都不懂,题目稍微变一下就不会了。

我建议按这个顺序走:先把前三个原理知识点吃透,然后花时间亲手判断注入点(第4、5点),再把联合注入和布尔盲注练熟(第6、8点),这两个是后续所有手法的地基。之后根据实际需要补充报错、时间、堆叠注入,接着再研究绕过对抗,最后用自动化工具提高效率,同时把防御部分作为收尾。这样从原理到防御形成闭环,无论面试还是实战,都不会只停留在“会用工具”的层次。

3. 注入点定位是第一步:别只盯着登录框

3.1 容易被忽略的输入位置

很多新手以为SQL注入就是登录框里输入' or 1=1--,实际上,只要是能被拼接到SQL语句里的外部输入,都可能是注入点。这里列几个我实际遇到过的高频位置:

  • URL参数:news.php?id=1product.php?category_id=5这种最常见。
  • POST表单数据:登录、搜索、注册信息里的字段。
  • Cookie中的值:有些系统会把用户ID、偏好设置存在Cookie里,服务端取出来直接拼SQL。
  • HTTP请求头:User-AgentX-Forwarded-ForReferer都可能被记录到数据库查询或日志写入操作中。

我印象比较深的一次授权测试,目标系统的X-Forwarded-For头会被获取并拼接到一条查询用户登录记录的SQL里,当时很多人只盯着页面参数测,完全没注意到这个头。这种位置隐蔽性高,扫描器也不一定能覆盖到,却很能体现基本功。

3.2 单引号、布尔判断和注释符的“侦查组合拳”

判断一个地方是不是注入点,核心思路就一句话:让SQL语句的结构发生可被观察的变化。最基础的操作序列是这样:

http://example.com/news.php?id=1 // 正常返回 http://example.com/news.php?id=1' // 多一个单引号,可能报错或返回异常 http://example.com/news.php?id=1 and 1=1 // 返回正常 http://example.com/news.php?id=1 and 1=2 // 返回异常

第四步是关键。and 1=2会让整个WHERE条件永远为假,如果页面返回内容和正常时不一样,说明我们输入的这段逻辑真的参与到了SQL执行中,即这里存在注入。

注释符的作用是“吃掉”后面的内容。比如原始SQL是:

SELECT * FROM users WHERE id='1' AND status='valid'

如果我们输入1' --,SQL会变成:

SELECT * FROM users WHERE id='1' -- ' AND status='valid'

--(注意后面跟一个空格)会把AND status='valid'整段注释掉,这样原来被限制的查询条件就被改写了。

3.3 数字型注入与字符型注入:同样是注入,判断逻辑完全不同

很多教程会把注入分成“数字型”和“字符型”,但这个分类容易让新手迷糊。我自己的理解是:这取决于后端SQL怎么写

如果SQL是WHERE id=$id,没有单引号包裹,用户输入1 and 1=1,拼接后是WHERE id=1 and 1=1,这是数字型注入,布尔判断可以之间生效。

如果SQL是WHERE id='$id',有单引号包裹,我们就必须先闭合前面的单引号,再构造逻辑。输入1' and '1'='1,拼接后是WHERE id='1' and '1'='1',这是字符型注入。

判断方法很简单:先输入1',看会不会报错;再尝试1' and '1'='1,看是否恢复正常。如果单引号直接导致报错,多半是字符型;如果单引号也不影响,可能是语句结构出了问题,那就得重新观察报错信息了。记住,注入的第一课不是学payload,而是学读懂数据库的“反馈”,认真看报错页面返回了哪些信息,这比盲目的payload糊脸有用得多。

4. 主流通用注入手法逐一拆解:从联合注入到时间盲注

4.1 联合注入:先数清楚字段,再找对回显位

联合注入是最直观、效率最高的一种利用方式,前置条件是页面查询结果能直接显示在响应里(有回显)。原理就是利用UNION关键字把额外查询的结果和原查询结果合并输出。

第一步是数字段数,最常用的方法是order by

http://example.com/news.php?id=1 order by 1 // 正常 http://example.com/news.php?id=1 order by 2 // 正常 http://example.com/news.php?id=1 order by 5 // 报错,说明字段数小于5

通过逐次尝试,确定表的字段数量。比如某个查询只有4个字段,order by 5就会报错。

第二步是定位回显位,把前面id改成不存在的值,让原查询的结果集为空,这样UNION选出的数据就能显示在页面上:

http://example.com/news.php?id=-1 union select 1,2,3,4

页面上显示了2和3,说明这两个位置可以直接输出内容。接下来就可以把查询语句替换到对应位置:

http://example.com/news.php?id=-1 union select 1,database(),user(),4

这样就能直接拿到数据库名和当前用户。之后就是查表名、查字段名、拖数据的过程。

这里有个经验:字段数如果很多,order by一个个试会很浪费时间,可以配合二分法或者直接写脚本跑。我自己在实战里更常用order by配合Burp Suite的Intruder模块做递增测试,几秒钟就能得出准确字段数。

4.2 报错注入:updatexml、extractvalue和floor该怎么选

当页面没有回显,但会展示数据库报错信息时,就可以用报错注入。原理是让SQL语句在计算时报错,同时把我们需要的数据带进报错信息里。

最常用的两个函数是updatexmlextractvalue。示例:

http://example.com/news.php?id=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1) http://example.com/news.php?id=1 and extractvalue(1,concat(0x7e,(select database()),0x7e))

concat(0x7e, ...)是拼接了~符号,这样做的目的是让报错信息中出现一个特殊字符,便于快速定位数据在报错内容里的位置。两个函数的限制类似,报错信息有长度上限(通常是32个字符左右),所以查询较长的数据(比如表名拼接)需要分段截取。

floor报错注入是另一种思路,它利用的是group bycount(*)冲突时产生的主键重复错误。这类payload写起来比较复杂,而且MySQL 5.1.5以上版本对报错内容的限制更严格,实际使用频率不如前面两个函数。

我在测试中遇到过一次比较尴尬的情况:页面把数据库报错信息给脱敏了,只显示“SQL错误”,但不回显具体内容。这时报错注入就失效了,只能走盲注。

4.3 布尔盲注:页面只有真假两种答案时的猜解策略

布尔盲注适合页面没有回显、也没有报错,但页面内容会因SQL结果真假而变化的情况。比如查询结果为真时显示“存在”,为假时显示“不存在”。

思路是把要猜解的内容逐字符拆开,通过substr函数取出某一个字符,再通过ascii函数转成数字,和猜想的数值做比较。示意:

http://example.com/news.php?id=1 and ascii(substr((select database()),1,1))>100

如果页面正常,说明数据库名的第一个字符的ASCII码大于100;继续二分,最终锁定精确值。然后是第2个字符、第3个字符,直到完整的库名、表名、字段名。

这种方法效率很低,但胜在稳定。实际工作中我很少手动一个字符一个字符猜,通常会写一个简单的Python脚本,或者直接让sqlmap跑布尔盲注。但手动练习一次非常有必要:它能让你深刻理解盲注的底层逻辑,这样工具跑不出结果时,你才知道问题出在哪。

4.4 时间盲注:sleep延时背后的网络噪音问题

当页面真假差异完全无法从内容上分辨,或者数据库报错被完全隐藏时,时间盲注就成了保底方案。原理是利用sleep()函数让数据库延时响应,再根据响应时间判断条件真假。

常规payload长这样:

http://example.com/news.php?id=1 and if(ascii(substr((select database()),1,1))>100,sleep(3),0)

如果ascii(...)>100为真,数据库就睡3秒,页面响应时间也会明显变慢。这样就把“内容差异”转换成了“时间差异”。

时间盲注有几个坑要特别注意。第一,网络本身有波动,判断延时阈值不能只靠肉眼,最好先测一下正常的响应时间基线,再设一个合理阈值(比如超过3秒算真)。第二,sleep()的秒数别设太大,防止单次请求等待过久,效率太低。第三,如果目标数据库不支持sleep()(比如某些数据库用pg_sleep()),payload就需要换函数。我在测试PostgreSQL时第一次就踩了这个坑,后来才记住不同数据库的时间函数差异很大。

4.5 堆叠注入:一条SQL不够用时的另类思路

UNION只能执行一条查询语句,而堆叠注入可以在同一个数据库连接里连续执行多条语句。原理是利用分号分隔:

http://example.com/news.php?id=1; create table test(id int)

如果数据库支持多语句执行,且应用没有做限制,create table这类语句也能被执行。堆叠注入的威力比UNION大得多,因为它不再受限于“查询”这一种形式,可以插入、删除、修改数据,甚至创建账号。

但它的限制也很明显。很多数据库连接默认不允许多语句执行(比如MySQL的驱动会关闭allowMultiQueries),同时堆叠注入不一定有回显,所以实用性比UNION低。我在CTF里见到比较多,真实系统里反而少见。学习时至少要知道它的存在和边界,不要在遇到UNION被拦死时完全没思路。

5. 绕过与变种对抗:真实攻防中更高频的“非标准注入”

5.1 万能密码:你以为理解了,实际还差一层

' or 1=1--是SQL注入的“Hello World”,几乎每个入门者都见过。它用在登录场景里的逻辑是:如果后端查询是SELECT * FROM users WHERE username='$user' AND password='$pass',我们输入admin' or '1'='1' --作为用户名,就能让整个条件成立,绕过密码校验。

但很多人只记住了payload,没理解闭合逻辑。真实开发中,如果使用了参数化查询,这种payload完全无效;如果老系统用的是拼接且把用户输入直接嵌入SQL,那还需要考虑语句中的引号闭合情况。不同的SQL写法,需要的payload结构不一样:

admin' or '1'='1' -- admin' or 1=1 -- ' or 1=1#

最后那个#也是MySQL的注释符,在URL里要编码成%23。我建议动手实验时,每种闭合方式都要亲自试一遍,搞清楚为什么同一场景需要不同的写法。知其然,也知其所以然,后面遇到过滤绕道时才不会懵。

5.2 宽字节注入:单引号被转义后的突破口

这个知识点是老生常谈,但很多人会忽略它背后的核心——字符集不一致。当应用使用addslashes这类函数对单引号加反斜杠转义时,输入'会变成\',这样单引号就失去了闭合作用。但在GBK等宽字节编码下,如果数据库和页面编码都是GBK,攻击者输入%bf%27%bf和反斜杠\会被解析成一个宽字节字符,导致后面的单引号“逃逸”出来。

输入:%bf%27 经过转义:%bf%5c%27 GBK解析:一个宽字节字符 + 一个单引号

所以宽字节注入能绕过的是基于反斜杠转义的过滤,本质问题是转义逻辑没有考虑数据库字符集。在现在以UTF-8为主流的Web环境里,宽字节注入的应用场景少了很多,但测试老系统时依然值得关注。遇到GBK编码的页面,第一时间就该想到这个方向。

5.3 二次注入:写入时过滤、读取时拼接的隐蔽路径

二次注入是我认为最“阴险”的一种注入,因为它绕过了很多防御者的直觉。很多开发者的过滤思路是:用户输入在写入数据库前做转义,只要入库时没有单引号、括号之类的字符,就认为安全了。

但二次注入的利用逻辑是:攻击者把payload作为普通数据写入数据库,入库时转义函数把单引号转成了无害字符,所以写入过程不会出问题。然而,后续某个功能从数据库读取这条数据,在另一个SQL语句里直接拼接使用,而拼接时没有再做转义,注入就爆发了。

典型的应用场景包括:用户注册时用自己的昵称,昵称被存储在数据库;后台某管理页面读取昵称后拼接进SQL查询,生成报表或日志。我在一次授权测试里就遇到过类似情况:一个用户资料编辑功能本身很安全,但管理端的用户导出功能把用户名拼进了查询语句,结果通过编辑用户名实现了一次完整的注入。

二次注入的可怕之处在于,单看任一个功能点都是正常的,必须从数据流转的完整链路去审查才会发现问题。

5.4 关键字过滤绕过:从注释符到等价函数的“同义替换”

很多系统会对selectunionor这类关键字做简单过滤。绕过思路有很多,我按使用频率从高到低排列:

  • 注释符拆分:sel/**/ect,把关键字中间插入注释,拼接后仍然能被解析为select
  • 大小写混合:SeLeCt,适用于大小写敏感过滤不严的场景。
  • 内联注释:/*!select*/,MySQL会执行注释内的内容。
  • 等价函数替换:substring换成midsubstrconcat_wsconcat
  • 编码绕过:URL编码、双重URL编码、十六进制表示字符串内容。

我自己测试时的经验是:先构造一个最小可用的payload,逐段替换关键字,观察哪一段被拦截。比如先输入union,看是否被过滤;再输入uniunionon(中间包一层),如果系统只做了简单的替换删除,这种写法就可能绕过。了解过滤机制的实现方式,比死记硬背绕过字典更重要。

5.5 WAF绕过:先判断拦了什么,再谈怎么绕

遇到WAF时,很多人的第一反应是找一个“WAF绕过payload”直接打。但正确的思路是完全反过来的:先判断WAF拦截了什么,再决定绕过策略

具体分三步。第一步,输入正常的请求,确认没有误拦。第二步,输入明显恶意的payload,比如1' and 1=1--,观察拦截特征(是返回403、还是返回自定义页面、还是直接空白)。第三步,把payload拆解成小块,逐段测试:单引号拦不拦?union拦不拦?select拦不拦?空格拦不拦?注释符拦不拦?

有一次我测试一个站点,union select被拦截,但union本身不拦,select也不拦,说明拦截规则是针对组合的关键词。这时候用union/*!50000select*/或者换行符绕过就有机会。还有一种情况是WAF只检测GET参数,不检测POST或Cookie,那就可以尝试把参数迁移到其他位置。

不过要强调一点:WAF绕过的知识体系非常庞大,而且每个WAF的实现都可能不同。入门阶段不需要死磕所有绕过姿势,但一定要掌握“隔离变量”的测试思路,这比任何绕过字典都通用。

6. 把知识变成能力:工具、靶场和练习路线

6.1 sqlmap的高级参数:level、risk和--technique的正确用法

sqlmap是SQL注入自动化检测的标杆工具,但很多人只停留在sqlmap -u URL --dbs这一层。实际场景里,默认参数扫描不到的情况很常见。

常用参数组合可以这么记:

# 基础用法,检测数据库 sqlmap -u "http://example.com/news.php?id=1" --dbs # 提高检测深度,level 3能测到HTTP头、Cookie等位置 sqlmap -u "http://example.com/news.php?id=1" --level 3 --risk 2 # 指定注入技术,布尔盲注情况下避免跑时间盲注 sqlmap -u "http://example.com/news.php?id=1" --technique=B # 指定数据库类型,减少误报 sqlmap -u "http://example.com/news.php?id=1" --dbms=mysql

--level控制检测的深度等级,从1到5。level=3时会测试HTTP头和User-Agent里的注入;level=5还包括Cookie--risk控制风险等级,risk=2会尝试or 1=1这类可能会造成数据变更的payload。--technique用于指定注入技术类型,B是布尔盲注、T是时间盲注、U是联合查询、E是报错注入。

我经常遇到初学者说“sqlmap跑不出来,目标一定没有注入”,其实多数时候只是参数配得不对。另外一个实操建议是:sqlmap跑批量检测时,一定要加--batch参数,否则中途会一直卡在交互确认上。

6.2 CTF与SRC场景下SQL注入的差异

CTF赛题里的SQL注入,更像一个“无菌实验室”:环境固定、flag位置明确、数据库结构已知或可猜。比如Web题里常见的SQL注入,目标就是拿到flag,可能藏在secret表里、可能在注释里、可能要通过堆叠注入才能读到。

SRC(安全响应中心)场景则完全不同。真实业务系统有各种限制:WAF、云防护、业务逻辑复杂性、数据隔离、审计日志等。在SRC平台测注入,首先要确认测试授权范围,其次要考虑影响面。很多漏洞平台都要求测试过程中不能拖库、不能破坏数据,这意味着sqlmap --dump这类操作在很多场景下是违规的。

所以我给想往实战方向走的朋友的建议是:CTF练的是“原理和速度”,SRC练的是“克制和判断”。两者都需要,但别用CTF的思路直接套真实系统。在SRC上发现一个注入点,先证明可以读取当前库名或用户信息,能证明危害就够了,不需要把整库拖下来。

6.3 靶场推荐与刻意练习节奏

我能稳定复现SQL注入相关手法的练习资源有以下几类:

  • sqli-labs:最经典的SQL注入靶场,从基础到进阶一共几十关,每一关对应一种注入类型。它的价值在于关卡设计贴近“手工判断”的训练目标。
  • DVWA:自带Web漏洞的综合靶场,SQL注入模块分为low、medium、high三个难度,适合观察同一漏洞在不同防护强度下的表现。
  • pikachu:中文靶场,覆盖了宽字节注入、二次注入等特殊场景,对理解“非标准注入”很有帮助。
  • CTF平台:各类CTF赛题中的Web方向,题目更灵活,适合检验综合能力。

练习节奏上,我建议按“重复”和“复盘”两个词来安排。第一遍,跟着教程慢慢打,记录每个payload对应的SQL变化;第二遍,关掉教程自己打,卡住了再去对照;第三遍,用sqlmap自动化跑一遍,对比手动测试和工具测试的结果差异。每一遍都能看到不同的细节。

7. 攻防一体:把这20个知识点反过来用

7.1 参数化查询为什么能“根治”注入

前面讲了那么多利用手法,核心都是“用户输入被拼接到SQL语句中并被当作代码执行”。那么防御的根本思路就是:让用户输入永远只是数据,不进SQL语句结构。参数化查询(预编译)正是这样做的。

以Java的PreparedStatement为例:

String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery();

这里的?是占位符,SQL语句的结构在数据库编译阶段就已经固定了,用户输入的usernamepassword只是被当作参数传递,无论输入什么内容,都无法改变语句结构。也就是说,即使输入' or 1=1--,数据库也只会把它当成一个普通的字符串值处理。

这也是为什么我反复强调,只做输入过滤是治标,参数化查询才能真正解决注入问题。对于存量系统的改造,逐条替换拼接SQL确实工作量很大,但这是从源头消除问题的唯一可靠路径。

7.2 最小权限和输入校验:数据库层与应用层的双保险

参数化查询是防线的主力,但光靠它还不够。数据库账号的权限如果过大,即使注入发生,攻击者也拿不到太多东西。

最小权限原则的落地姿势包括:应用连接数据库的账号,只授予它必要的增删改查权限;如果业务只需要查询,那就只给SELECT权限;禁止应用账号使用FILEGRANT这类高危权限;日常操作不使用root级别的账号连接数据库。

应用层的输入校验同样不能省。虽然输入校验无法完全替代参数化查询,但它能拦截大量明显恶意的请求,降低被扫描器盯上的概率。校验要基于“白名单”思维:规定每个字段应该是什么格式,比如ID只能是数字,用户名只能包含字母数字和下划线,而不是简单地去黑名单拦截一些关键字。

7.3 从日志中一眼认出SQL注入攻击

防御做得再好,也需要监控和感知能力。SQL注入攻击在日志里有很强的特征,完全可以靠规则发现,常见特征包括:

  • 请求参数中包含' or 1=1union selectsleep(等典型payload片段。
  • 同一个IP在短时间内反复请求同一个URL,且参数值在频繁变化。
  • 请求参数中夹杂着大量编码后的字符,比如%27(单引号的URL编码)、%23(#注释符)。

我自己在用日志平台做检测时会配置类似下面的正则规则来匹配关键词:

(union[\s]+select)|('?or'?\s*1=1)|(sleep\()|(updatexml\()|(extractvalue\()|(0x[0-9a-f]{8,})

命中这些特征就自动告警,再结合IP、时间、URL做聚合分析,基本能定位到可疑扫描或利用行为。当然,攻击者也在不断变种绕过这些规则,所以日志监控需要长期迭代,但不能因为规则不完美就不做。

SQL注入这个专题,真正拉开差距的,不是背了多少条payload,而是能不能在一条请求过来时,快速判断出它背后的SQL长什么样;在写代码时,能不能一眼看出某个拼接会出事。把上面这20个知识点吃透,然后去靶场里把手弄脏,你才能对“为什么一个老漏洞能活二十多年”这件事有真正的体感。

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

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

立即咨询