ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SQL注入攻击手法与六层纵深防御体系全解析

SQL注入攻击手法与六层纵深防御体系全解析 做应用安全这些年被问得最多的一个问题不是“怎么防SQL注入”而是“这漏洞是不是已经过时了”。每次听到我都挺无奈——攻击手法确实在翻新防御体系也在演进但线上系统真到授权测试的时候随手一条 or 11探进去照样有惊喜。这篇文章想把SQL注入这件事彻底聊透不堆名词从三条最经典的攻击手法讲起再落到六层防御体系一条条说清楚为什么有效、为什么有时候会失效。无论你是刚入行写SQL的开发者还是带团队的技术负责人看完至少对“注入从哪来、怎么挡、为什么还会被绕过”心里有个数。安全提示本文涉及的所有payload与测试技巧只能在DVWA、Pikachu、sqli-labs、CTFHub这类本地靶场以及你拥有书面授权的目标上进行。拿未授权目标练手既违法也违背安全工作的底线。1. 别小看SQL注入本质、现状与危害很多开发觉得SQL注入是“上古漏洞”是教程里编出来的段子。实际情况恰恰相反这些年我参与授权测试时依然能在教育、政务、企业内部系统里看到非常原始的注入点。要理解为什么它这么难绝迹得先回到问题的源头。1.1 SQL注入的本质代码和数据边界失守SQL注入的本质就一句话不该被执行的数据被当成了代码执行。开发者把用户可控的输入直接拼进SQL语句等于让用户在你原本写死的查询逻辑里再自由发挥一段。拿最常见的登录场景举例下面这段代码就是最经典的错误示范$sql SELECT * FROM users WHERE username . $_POST[username] . AND password . md5($_POST[password]) . ;如果username填的是admin or 11 --拼接出来的SQL就变成了SELECT * FROM users WHERE username admin or 11 -- AND password ...--是SQL注释符后面内容直接被注释掉整个WHERE条件变成恒真密码校验等于摆设。这里可以打一个生活化的比方SQL注入就像餐厅后厨完全按照客人说的字面信息做菜。你说“多加辣”没问题你要说“多加辣顺便把隔壁桌的菜端给我”后厨也照做。程序把用户输入直接拼进SQL就是允许用户向后厨下达任意指令。问题的根源是程序和用户之间没有边界用户输入本来是“数据”结果被当成了“命令”。真正的SQL注入又不止于登录绕过只要任何参数被拼进SQL而且这个参数用户可控就可能存在注入。GET参数、POST参数、Cookie、HTTP头、JSON请求体里的字段全都可以成为注入入口。我见过不少系统只过滤了$_GET和$_POST结果攻击者把payload放在Cookie或User-Agent里照样打进去。1.2 现在还存在SQL注入漏洞吗“现在还存在SQL注入漏洞吗”这个问题每隔一段时间就会被人翻出来问一次。坦白讲存在而且远比想象中普遍。OWASP Top 10最近几个版本里注入类漏洞始终稳居前列。我自己的体感是做授权的项目里每年依然能遇到好几个因为历史接口没做参数化导致的注入点。为什么现代框架已经把参数化查询内置到ORM里了漏洞还是消不掉原因大概是这几类历史系统改造难。很多系统跑了十年以上开发早换了几拨人接口文档缺失没人敢动核心查询逻辑只能拿过滤函数打补丁。开发者对预编译理解有偏差。很多人知道用MyBatis却不知道${}是字符串拼接也不知道ORDER BY、动态表名这类场景根本没法用占位符。低代码平台和报表系统兴起这些平台为了灵活性经常允许用户写“自定义SQL条件”结果把注入面重新打开。绕过思维在持续进化。过滤函数写得再全攻击者也能用注释符、大小写、等价函数、URL编码把payload改得面目全非。换句话说现代安全体系能挡住“脚本小子”却挡不住真正理解SQL和数据库特性的测试人员。1.3 注入一旦被利用影响有多大SQL注入的危害通常被低估很多人以为它只是“能多看点数据”。实际上注入的影响范围取决于两个东西漏洞位置的权限和数据库账户的权限。风险类型攻击者可能做的事对业务的影响数据泄露遍历查询库名、表名、字段名批量导出用户数据拖库隐私数据在暗网流通平台口碑崩塌认证绕过通过万能密码直接登录后台后台被接管业务配置被篡改数据篡改执行UPDATE/DELETE批量改密码、删订单、删日志业务数据不可信甚至直接瘫痪提权与命令执行利用数据库高权限账号写文件、调用扩展执行系统命令网站服务器沦陷内网被横向渗透审计破坏删除或篡改数据库日志、访问日志溯源困难事故原因无法定位很多人以为sqlmap跑一下只是“脱个库”但在我经历的真实授权项目里注入点一旦连的是sa或root这类高权限账号攻击者很快就能从“数据库沦陷”走到“服务器控制权沦陷”。这就是为什么我一直强调防御SQL注入要当成一件体系化的事来做而不是在代码里加个过滤函数就完事。2. 三种典型攻击手法拆解SQL注入的手法经过多年演化分支很多但最常见、最实用的其实就三类联合查询注入、盲注、报错注入。搞懂这三类基本就能覆盖绝大多数注入场景。2.1 联合查询注入让数据像在自选超市里一样任取联合查询注入依赖的场景是页面会把SQL查询结果直接显示出来而且攻击者能猜出当前查询的字段数量。核心就是利用UNION SELECT把自定义查询结果拼到原查询后面。完整的思路在DVWA的low级别里非常典型手工测试流程大概是第一步确认存在注入点。在参数后加一个引号看是否报错或者用逻辑判断1 and 11 -- 1 and 12 --第一种情况页面正常第二种情况页面无结果或报错说明我们的输入确实影响了SQL结果。第二步猜字段数量。用ORDER BY1 order by 1 -- 1 order by 2 -- 1 order by 3 --ORDER BY后面跟数字表示“按第几列排序”如果指定列数超出查询结果列数数据库会报错。比如order by 3报错、order by 2正常说明当前查询只有2列。这一步必须放在UNION之前因为UNION要求前后查询的字段数必须一致。第三步找页面回显位置1 union select 1,2 --页面如果显示了你传入的数字说明这两个位置能把数据直接显示出来。第四步开始拖数据。先拿库名再拿表名、字段名最后拿数据1 union select 1,database() -- 1 union select 1,group_concat(table_name) from information_schema.tables where table_schemadatabase() --information_schema.tables是MySQL存放元数据的系统表group_concat可以把多条查询结果拼成一行这是手工注入时非常高效的取数方式。拿到表名后再查information_schema.columns拿字段名最后直接查业务数据。联合查询注入的前提是“有回显”也就是查询结果会原样输出到页面上。如果页面没有回显、只返回“查询成功/失败”这条路就走不通得换盲注。2.2 布尔盲注与时间盲注没有回显也能一点一点“抠”出数据真实业务里很多接口不会把查询结果直接打到页面上只会返回“正常/不正常”“登录成功/失败”。这时候注入还在但看不见数据只能用盲注逐字符猜。布尔盲注的思路是让条件成立时页面走正常逻辑条件不成立时页面走异常逻辑以此当“是/否”信号。比如这样kobe and left(database(),1)p --如果库名第一个字母是p页面正常不是p页面空白。攻击者就这样一个字符一个字符地猜完整库名、表名、字段名和数据内容。效率很低却很有效。时间盲注更暴力一点不依赖页面差异而是靠“延不延时”来判断条件。比如1 and if(length(database())3,sleep(3),0) --如果库名长度大于3数据库会睡3秒再返回结果否则立即返回。延时成了“是/否”信号。盲注的过程是重复劳动适合写脚本自动化。这里给一个Python布尔盲注脚本的示例改成你自己靶场的URL就能跑import requests # 以你自己搭建的Pikachu靶场URL为准 url http://127.0.0.1/pikachu/vul/sqli/sqli_str.php cookie {PHPSESSID: 你的会话ID} def is_true(condition): payload fkobe and {condition} -- r requests.get(url, params{name: payload}, cookiescookie) return kobe in r.text # 根据靶场页面差异调整判断条件 # 先猜库名长度 db_len 0 for i in range(1, 30): if is_true(flength(database()){i}): db_len i break print(database length:, db_len) # 二分法逐字符猜库名 db_name for pos in range(1, db_len 1): low, high 32, 128 while low high: mid (low high) // 2 if is_true(fascii(substr(database(),{pos},1)){mid}): low mid 1 else: high mid db_name chr(low) print(database:, db_name)这个脚本里最关键的是二分法ascii把字符转成数字substr逐个取字符mid的判断把范围一分为二把字符猜出来的平均次数从128次降到7次左右。盲注慢但有了二分法效率能提升一个数量级。requests库需要提前安装pip install requests。写这类脚本的时候注意判断页面差异的条件要跟靶场实际情况对齐不同靶场页面结构不同返回内容也可能不同。2.3 报错注入让数据库把秘密“骂”出来报错注入是MySQL里一个挺“取巧”的手法。它的思路是故意触发数据库报错让数据库把查询结果带进错误信息里。最常用的两个函数是updatexml和extractvalue1 AND updatexml(1,concat(0x7e,database()),1) -- 1 AND extractvalue(1,concat(0x7e,user())) --原理上updatexml是MySQL用来更新XML文档的函数第二个参数要求是合法的XPath表达式。如果传入的字符串不是合法XPathMySQL会抛出格式错误并把这条字符串原样带回错误信息中。concat(0x7e,database())里的0x7e是波浪号~的十六进制表示用来让拼接结果明显“不合规”确保报错。报错注入最大的坑是报错信息有长度限制通常只能带出约32个字符。数据一长就截断所以拖比较长的数据时依然要配合substr和ascii分段处理1 AND updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schemadatabase()),1,32)),1) --三种手法各有适用场景整理成表格方便对照手法回显条件速度核心要点联合查询结果直接显示在页面快靠UNION SELECT拼接必须字段数一致布尔盲注页面有对比差异慢但稳定逐字符猜解配合二分法提速时间盲注任何场景都能用很慢靠sleep延时判断容易受网络波动影响报错注入MySQL且报错能显示到页面较快靠XPath函数把数据带进错误信息注意32字符截断2.4 万能密码与认证绕过的前世今生“万能密码”是SQL注入最出圈的应用场景以至于很多非安全圈的人也听说过。它本质上不是一种独立手法而是注入在“认证逻辑”里的实际利用。最经典的payload就是admin or 11 --把它放进登录表单的username字段拼出来的SQL变成SELECT * FROM users WHERE username admin or 11 -- AND password ...or 11恒为真后面密码条件又被注释掉整条查询直接返回第一行用户通常是管理员账号。这里有个经常被忽略的技术细节MySQL的--注释符后面必须带空格否则不会被识别成注释。所以很多payload写成--因为加号在URL里会被解析成空格。MySQL里也可以用#作注释符#后面不需要空格更方便。万能密码能打穿某些系统的原因并不复杂一种情况是代码把用户名和密码都拼进了SQL另一种情况是过滤函数只处理了参数名没处理参数值里的特殊字符。我自己排查询单的时候还遇到过登录逻辑是where username$u or email$u and password$p这种写法优先级直接把认证条件改写的案例。所以不要觉得万能密码是“小孩把戏”它在登录接口设计得不够健壮的系统上依然有奇效。3. 靶场实操一条完整的注入探测路径理论讲完一定要动手。没有靶场的练习都是纸上谈兵好在现在本地搭靶场的成本已经很低一台普通笔记本就能搞定。3.1 靶场怎么选DVWA、Pikachu、sqli-labs与CTFHub对比搜索“SQL注入靶场”的时候出现频率最高的是这几个DVWA、Pikachu、sqli-labs、CTFHub技能树。它们定位不太一样我按自己的练习顺序推荐靶场难度梯度适合谁特点DVWAlow/medium/high/impossible四级零基础入门有完整的等级设置同一漏洞逐步加防护非常适合理解攻防对抗sqli-labs60关逐步进阶想练手工注入的人每一关一个知识点从字符型、数字型到各种绕过是手工注入的地狱训练场Pikachu按漏洞类型分模块想覆盖多种漏洞的初学者国内团队做的靶场有SQL注入、XSS、CSRF等关卡设计贴近开发场景CTFHub技能树按知识点分类想刷题巩固的人按“技能树”方式组织SQL注入分得很细适合查漏补缺我的建议路线是先用DVWA把low等级通关理解联合查询、盲注、报错注入分别长什么样再去sqli-labs一关一关地练手工注入把字符型、数字型、搜索型、排序型这些细分场景都过一遍然后用Pikachu练综合场景顺便感受一下宽字节注入这类经典绕过。CTFHub技能树适合碎片时间刷题针对性补弱点。所有靶场都建议在本地用Docker搭建不要用公网在线靶场既不稳定也有泄露测试数据的风险。3.2 手把手完整链路从发现注入点到拿全数据我在DVWA的low等级里演示一遍完整链路。先把DVWA的安全等级调到low进入SQL Injection页面URL大概是/dvwa/vulnerabilities/sqli/?id1SubmitSubmit。第一步探测注入点。输入1页面正常返回用户信息。接着输入1 and 11 --页面正常输入1 and 12 --页面空白。这已经能说明参数被拼进了SQL而且我们能通过逻辑条件控制查询结果。第二步用ORDER BY数一下字段数量。试到order by 3报错说明原查询只有2列1 order by 1 -- (正常) 1 order by 2 -- (正常) 1 order by 3 -- (报错)第三步确认回显位置1 union select 1,2 --页面显示First name是1Surname是2两个回显点都在。第四步拖库、拖表、拖字段、拖数据1 union select 1,database() -- 1 union select 1,group_concat(table_name) from information_schema.tables where table_schemadatabase() -- 1 union select 1,group_concat(column_name) from information_schema.columns where table_nameusers -- 1 union select 1,group_concat(user_id,0x3a,user,0x3a,password) from users --0x3a是冒号的十六进制用来把多列数据拼接成一个整体显示。到这一步用户名和密码哈希都展现在眼前了。这里要特别说明DVWA是本地靶场这才是“实战”的合法前提。你在任何未授权的系统上重复这套操作后果完全不同。3.3 手工验证和sqlmap工具怎么配合手工能解决的问题为什么还要用工具我的观点是手工负责“理解”工具负责“效率”。当你已经能手工判断出注入类型和参数位置再用sqlmap批量拖数据会省很多时间。sqlmap的基本用法sqlmap -u http://127.0.0.1/dvwa/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSIDxxxx; securitylow --dbs带--cookie是因为DVWA需要登录态不带的话扫描不到。后面可以继续用-D dvwa --tables、-T users --columns、-C user,password --dump逐级拖数据。我踩过的坑是sqlmap默认跑起来很慢因为会做大量payload变体和注入类型探测。如果已经知道是字符型联合查询可以直接加--techniqueU限定只测联合查询速度会快很多。反过来如果盲注场景--techniqueB或--techniqueT会让流程更聚焦。但工具不等于一切。sqlmap跑不出来的场景太多了需要多步登录态的接口、被WAF拦截但有绕过空间的参数、特殊位置如排序字段和JSON体里的参数这些地方恰恰是人工的用武之地。所以我的习惯永远是先手工确认再上工具批量取数。4. 六层防御体系纵深防御才是唯一出路前面讲攻击手法是为了让防御更有针对性。接下来进入正题六层防御体系每一层我都说清楚防什么、怎么防、为什么有效、常见误区是什么。六层分别是参数化查询、输入校验、最小权限、框架/ORM边界、WAF与运行时防护、审计测试与运维。它们的关系不是“装一个就行”而是层层递进、互相兜底。4.1 第一层参数化查询与预编译——承重墙级别的防线参数化查询是防SQL注入最重要的一层没有之一。它的核心原理是SQL语句结构先固定参数通过占位符传递数据库编译SQL时只把结构编译一次参数不参与编译。就算参数里写满or 11它也只是一个字符串值不可能改变SQL逻辑。PHP里用PDO的写法$stmt $pdo-prepare(SELECT * FROM users WHERE username ? AND password ?); $stmt-execute([$username, $password]);Java里用PreparedStatementString sql SELECT * FROM users WHERE username ? AND password ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password);MyBatis的写法更常见但这里有个大坑#{}是预编译${}是字符串拼接一个安全一个危险。!-- 安全写法 -- select idgetUser resultTypeUser SELECT * FROM users WHERE username #{username} /select !-- 危险写法 -- select idgetUser2 resultTypeUser SELECT * FROM users WHERE username ${username} /select${}常见于动态排序字段、动态表名、like模糊查询、in列表这几种场景。有人会把用户传进来的排序字段直接写进${}还觉得“只是排序字段没关系”。实际上攻击者在排序字段后拼一条and updatexml(1,concat(0x7e,database()),1)照样能出数据只是位置比较冷门。这几种场景的正确做法不是继续拼接而是在代码里做映射。比如排序字段写一个白名单数组{id:id, time:created_at, name:username}用户传什么key都由代码查一下映射表永远不直接使用用户输入作为SQL片段。动态表名同理提前枚举合法值。注意参数化查询解决的是“占位”问题不能解决“结构”问题。凡是SQL里需要变化的结构部分比如列名、表名、排序方式占位符都帮不上忙只能靠白名单映射。4.2 第二层输入校验与白名单——把脏数据挡在门外输入校验是第二道防线。思想很简单对每个参数明确它应该长什么样然后只接受长成那样的东西。数字ID强转int或integer类型PHP里直接$id (int)$_GET[id];比任何正则都靠谱。邮箱用框架自带的校验规则。用户名限定字符集和长度比如^[a-zA-Z0-9_]{3,20}$。排序字段、状态字段、日期范围直接和合法值列表比对。常犯的错误是拿黑名单过滤比如正则匹配掉select、union、or这些词。黑名单的思维本身就靠不住因为绕过方式太多了大小写混淆、注释符插入、URL编码、等价函数替换。你用正则挡了select攻击者用/*!50000select*/照样过。转义函数也有边界。像PHP早期的addslashes、mysql_real_escape_string只对字符串内容里的特殊字符做转义遇到数字型注入、LIKE模糊搜索、ORDER BY位置基本无效。把转义当作唯一防线等于天天跟攻击者玩黑名单猜谜游戏。输入校验真正的定位是“减少攻击面”而不是“替代参数化”。它可以把绝大多数普通攻击挡在门外让参数化那层防线更从容。4.3 第三层数据库最小权限——即使出漏洞也减损最小权限原则的意思是Web应用连接数据库时用的账号权限应该小到只够完成业务功能。这是安全里的“减损”思维——如果某层防线失守了权限还能把损失锁在可控范围内。很多系统为了省事用sa或root账号连数据库这是最要命的习惯。攻击者一旦拿到注入点就等于拿到了数据库管理权限脱库、写文件、调存储过程、开xp_cmdshell执行系统命令一条龙全覆盖。合理的账号分配应该是这样的-- 单独创建web应用专用账号只授最基础的DML权限 CREATE USER webapplocalhost IDENTIFIED BY StrongPass#2024; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO webapplocalhost; -- 不要给FILE、SUPER、GRANT、CREATE等权限业务需要做DDL变更时用专门的DBA账号在变更流程里执行而不是让Web应用拿着建表权限跑。后台管理功能如果确实需要更大权限也应该单独用一个受限账号与前端业务账号隔离。为什么这个能防注入因为注入能拿到的数据范围完全取决于连接账号的权限。SQL Server里就算被注入账号没有sysadmin权限攻击者也没法直接开xp_cmdshell执行命令。MySQL里没有FILE权限INTO OUTFILE写木马就直接失败。数据库账号权限越低注入被利用的杀伤半径越小。4.4 第四层框架与ORM的安全边界——别把原生SQL当后门现代框架的ORM大多内置参数化查询但框架不是免死金牌。它的安全边界只覆盖“走标准API”的情况只要你开了原生SQL的口子风险立刻回来。MyBatis里select配#{}是安全的${}是危险的。JPA里使用createQuery写JPQL时如果拼接字符串同样会引入注入。Hibernate虽然做了很多转换但原生SQL查询依然支持拼接写法。还有一个隐蔽风险在动态查询构造器里。很多团队用MyBatis-Plus或QueryDSL这种查询构造器觉得“用构造器就安全”实际上构造器只是帮你生成SQL最终能不能防注入取决于基础条件是否参数化。有些构造器为了支持动态排序会在底层引入拼接这个要格外留意。正确做法是把框架的安全能力当成默认选项同时立一条规矩项目里不允许出现“用户输入值直接拼进SQL片段”的代码凡是需要动态SQL的场景必须走白名单映射或显式参数绑定。代码评审时重点盯${}、concat、String.format这类危险函数。4.5 第五层WAF与运行时防护——网络侧的拦截与兜底WAF是网络层面的防护部署在应用前面通过规则分析HTTP请求把疑似注入的payload拦截掉。常见实现有正则规则、协议解析、语义分析三类。部署位置可以是硬件、软件、云WAF。WAF能挡掉大多数“已知攻击”但它的第一个问题是误报。业务里本身含有关键字比如用户搜索“select”“or”这类词的请求很容易被误拦截影响正常业务。第二个问题是绕过的空间太大。攻击payload变体极多大小写、注释符、等价函数、长短不一规则引擎很难穷举。所以WAF只能作为兜底不能作为主力。比WAF更接近业务的是RASP运行时应用自我保护。RASP嵌在应用运行环境里在代码执行到SQL操作那一瞬间做检测能分辨“这个参数是正常业务输入还是真跑到了SQL执行路径”误报率比WAF低很多也能防住一些WAF看不出来的变形payload。数据库防火墙也值得提一下它直接监听数据库流量能发现“同一个应用账号突然执行了大量非常规查询”这类特征在数据库层面阻断异常行为。比如正常业务每秒查询几十次突然变成每秒几万次数据库防火墙会立刻报警并阻断。4.6 第六层审计、测试与安全运维——把漏洞消灭在闭环里防御体系的最后一层是把安全融入研发和运维闭环保证前面几层持续有效而不是部署完就再也不看。代码审计上线前在代码仓库里全局搜索concat、$_GET、${}、createQuery、String.format这类危险模式给开发列清单。自动化扫描用DAST工具在测试环境跑一轮常见注入payload至少把非盲注场景验证掉。人工渗透测试自动化工具覆盖不了的盲注、业务逻辑注入、排序注入需要经验丰富的人做手工验证。定期做一次比临时抱佛脚强得多。日志监控数据库慢查询里突然出现大量sleep、if、union特征或者同一个IP在短时间内请求了海量带引号的参数都是明显信号应该立刻告警。漏洞管理发现漏洞后要记录、修复、复测形成闭环。没有复测的修复等于没有修复。这层的核心是“让漏洞被尽早发现、被正式流程管理”。我在实际项目里见过太多公司不是没有安全工具是安全工具产生的告警没人看漏洞修完不复测运维和研发各自为政。第六层不解决具体某个漏洞解决的是“漏洞管理机制”本身。5. 常见问题与排查技巧实录最后把实战中经常遇到的几个问题集中梳理一下这些基本是日常排查时的高频场景。5.1 万能密码为什么还能打穿某些后台排查万能密码打穿后台的问题时我一般从三个地方找源头第一登录接口是否参数化。如果代码还在直接拼接用户名密码万能密码必然有效。修复方式是改成预编译。第二过滤有没有覆盖所有输入位置。常见疏漏是只处理了$_POST但登录请求是JSON格式或用户名放在Header里过滤函数根本没碰到。第三登录逻辑本身有没有额外的OR条件。比如有的系统支持“用户名或邮箱”登录SQL写成where username$u or email$u and password$p一个引号就能把认证条件改得面目全非。5.2 SQL Server 2008这类老系统如何加固搜索“sql server 2008注入”的人多半是在排查老系统。SQL Server 2008已经停止官方更新这意味着新发现的漏洞没有修复补丁风险只会累积。加固思路按照短期缓解和长期治理来短期应用层全面参数化禁止所有拼接SQL数据库账号改成最小权限严禁用sa连接应用关闭xp_cmdshell等危险组件用EXEC sp_configure xp_cmdshell, 0关掉数据库对外开放的端口只对内网管理网段开放启用数据库审计日志记录异常SQL操作。长期推动系统迁移到受支持的新版本数据库这是唯一的根本解。老数据库上堆再多加固手段也只是在给计时炸弹加缓冲。注意这类加固动作应该在变更窗口内执行改完要做业务回归测试。5.3 扫描器漏报注入怎么办自动化扫描器漏报SQL注入常见原因有四个扫描器没有登录态。大量注入点只对登录用户可见不带Cookie就什么都扫不到。参数位置不在扫描器视野内。JSON请求体、XML字段、自定义Header、Cookie里的参数很多扫描器根本不测。应用存在全局过滤。第一层校验把明显payload拦掉了扫描器就判定“不可注入”实际上用绕过变体还能打。盲注场景太耗时。时间盲注验证一次要等好几秒扫描器为了控制时长会直接跳过。解决思路扫描器只作为辅助主要靠人工测试。测试范围要覆盖所有参数包括Header、Cookie、JSON字段。如果开发能提供一个带登录态的测试账号给扫描器配上会话检出率会有明显提升。5.4 攻击者绕过滤的盲点也是你自查的清单从防御视角整理一份容易漏掉的位置清单这些地方既是攻击者的目标也是自查的重点ORDER BY/GROUP BY动态排序字段。很多系统只过滤了查询条件参数排序字段直接拼进SQL这里是最常见的盲区。LIKE模糊搜索。攻击者在搜索词后注入通配符和闭合符或者利用转义符干扰。动态表名、动态库名。报表系统、多租户系统经常会按参数选表这个位置参数化帮不上忙必须白名单映射。批量操作接口。一次处理多条数据的接口可能在循环里重复拼接SQL每一条都可能成为注入点。JSON/XML日志记录型参数。有些系统会把原始报文拼进审计日志的SQL攻击者伪造报文内容就能打进去。自查的时候拿一份真实业务请求把里面每个参数挨个在“是否能拼进SQL”的角度过一遍比泛泛扫描有效得多。最后再分享一条个人经验防御SQL注入我看过最靠谱的团队不是把某个工具用得天花乱坠而是把“统一参数化、动态片段白名单映射、数据库最小权限”这三件事焊死在开发规范里。每一条规则背后都有真实的教训。如果你现在还不知道从哪下手先把代码仓库里所有${}和字符串拼接SQL列出来一个个改成参数化写法。改完再回头问“SQL注入还存在吗”你会得到完全不一样的答案。
返回列表