SQL注入总概述


没问题,咱们不用表格,我给你按模块拆解得更详细、更口语化一点,把每个点的意思、怎么用、有啥区别都讲清楚👇


一、SQL注入的「基础分类维度」

这部分是你拿到一个网站,判断"它有没有注入、怎么注入"的核心依据,一共分4个维度。

1. 数据库类型

不同的数据库,语法、注入函数、可利用的特性都不一样,是你后续写注入语句的前提。

  • MySQL:最常见的开源数据库,也是入门学习的重点。它自带information_schema这个系统库,里面存了所有表名、字段名,是联合查询注入的关键;同时支持sleep()、benchmark()这类延时函数,方便做盲注。大部分中小网站用的都是它。
  • MSSQL(SQL Server):微软的数据库,多见于Windows平台的企业系统。它的特点是权限高的时候能调用xp_cmdshell直接执行系统命令,注入的破坏力会更大,但语法和MySQL有不少差异,比如注释符、系统表都不一样。
  • Oracle:大型企业级数据库,权限控制非常严格,注入场景相对复杂。一般很少能直接拿到系统命令,大多是通过错误回显、存储过程或者utl_http这类扩展包来利用,门槛比MySQL高很多。
  • Access:轻量级的桌面数据库,多见于老的ASP网站。它没有独立的数据库服务,也没有information_schema,注入的时候大多靠猜解表名,而且不支持联合查询,方法比较受限。
  • 其他:比如PostgreSQL、MongoDB这类,MongoDB属于NoSQL,注入逻辑和SQL完全不一样,属于单独的分支。

2. 提交方式(注入点在哪里)

指的是你把恶意SQL语句提交给服务器的渠道,决定了你要改哪里的参数。

  • GET提交:最常见的方式,参数直接拼在URL里,比如?id=1、?name=admin。你直接在浏览器地址栏修改参数就能测试,比如改成?id=1 and 1=2,看页面会不会报错。
  • POST提交:参数放在HTTP请求体里,一般是表单提交、接口传参的时候用,比如登录框、注册页、搜索框。这种你没法直接在地址栏改,得用抓包工具(比如Burp Suite)把请求抓下来,修改里面的参数再发出去。
  • COOKIE提交:参数放在请求的Cookie字段里,比如很多网站会用Cookie存用户ID、会话信息。这种方式常用来绕过一些简单的参数过滤,因为很多WAF对Cookie的检测会比URL参数松一点。
  • REQUEST提交:这个不是一个独立的提交方式,而是PHP里的一个超全局变量,它会同时接收GET、POST、Cookie传过来的参数。也就是说,你不管用GET还是POST提交,它都能接收到,这种情况你得实际测试一下,看哪种方式能生效。
  • HTTP头提交:注入点藏在HTTP请求头里,比如User-Agent(浏览器标识)、Referer(来源页面)、X-Forwarded-For这些字段。这种情况多见于后端会把请求头的信息存到数据库里,或者用请求头做日志记录,恶意的请求头就会被当成SQL语句执行。
  • 其他:比如文件上传时的文件名、JSON请求体里的参数、WebSocket的消息内容,这些都可能成为注入点,属于比较特殊的场景。

3. 数据类型(怎么构造闭合语句)

指的是你提交的参数,在后端SQL语句里是什么类型,决定了你写注入语句时要不要加引号、怎么闭合。

  • 数字型:参数直接作为数字参与SQL运算,后端的SQL语句大概是select * from users where id = 1,参数没有被引号包裹。这种情况你直接拼接SQL语句就行,比如?id=1 and 1=2,不需要额外处理引号。
  • 字符型:参数被单引号或者双引号包裹,比如后端语句是select * from users where name = 'admin'。这时候你直接加and 1=2是没用的,因为它会被当成字符串的一部分。你得先把引号闭合,比如改成?name=admin' and 1=2 --,这里的'把前面的字符串闭合了,--是注释符,把后面的单引号注释掉,这样and 1=2就能被当成SQL语句执行了。
  • 其他类型:比如日期型参数,后端语句可能是select * from logs where date = '2025-01-01',这种也属于字符型的一种,需要用引号闭合;还有布尔型参数,比如?status=1,本质上也是数字型,判断逻辑和数字型一样。

4. 查询方式(注入依托的SQL语句)

指的是你的恶意语句,是拼接到哪一类SQL操作里执行的,不同的操作能做的事不一样。

  • select查询:最常见的场景,比如查询用户信息、商品信息、文章列表。这是联合查询注入、盲注的主战场,目标就是偷取数据库里的数据,比如管理员账号密码。
  • insert插入:比如注册、留言、评论这类操作,后端会执行insert into users (name, pass) values ('admin', '123')。你如果在用户名的位置注入,比如填admin', (select pass from users where id=1) --,就可能把管理员的密码写到你的用户名里,或者直接插入一条管理员账号。
  • delete删除:比如删除留言、订单,后端语句是delete from messages where id = 1。注入的话,比如?id=1 or 1=1,就会把表里所有数据都删掉,破坏力很大。
  • update更新:比如修改密码、修改个人信息,后端语句是update users set pass='123' where id=1。注入的话,比如修改成update users set pass='123' where id=1 or 1=1,就会把所有用户的密码都改成你设置的值。
  • order by排序:很多网站会用order by id或者order by name来排序数据,参数可控的话就会产生注入。最常见的用法是判断查询的字段数,比如order by 1正常,order by 5报错,说明这个查询有4个字段,这是联合查询注入的前提条件。

5. 回显/盲注(注入的核心分支)

这是SQL注入最关键的分类,直接决定了你用什么方法攻击。

  • 回显注入:就是你执行SQL语句后,结果会直接显示在页面上。比如你用union select拼接了查询管理员账号的语句,页面上就会直接显示出账号和密码。这种攻击效率最高,不用猜,直接拿数据。
  • 无回显注入(盲注) :页面不会直接显示SQL执行的结果,你只能通过页面的变化来间接判断语句执行的结果,分两种:
    • 布尔盲注:页面只有"正常"和"异常"两种状态,比如and 1=1页面正常,and 1=2页面异常,你就可以通过构造条件,比如and ascii(substr(database(),1,1))=115,逐位猜解数据库名的每一个字符。
  • 延时盲注:利用sleep()这类延时函数,比如and sleep(5),如果页面响应时间明显变长,说明语句执行成功了。你可以通过控制延时的时间,来判断条件的真假,比如猜解字符的时候,猜对了就延时5秒,猜错了就正常返回。

二、WAF绕过技术

WAF(Web应用防火墙)会识别并拦截常见的注入语句,绕过的核心思路就是"改变语句的形式,但不改变它的逻辑",常见的方法有这些:

  • 更改提交方法:比如原来的GET请求被拦截了,改成POST提交;或者把参数拆分到多个位置,比如把id=1改成id=1放到URL里,and 1=2放到Cookie里,让WAF没法完整匹配。
  • 大小写混合:WAF很多时候只会匹配小写的关键词,比如select,你改成sElEcT、UNion,就能绕过一些简单的规则。
  • 加解密编码类:比如URL编码,把空格改成%20,把单引号改成%27;或者用Unicode编码、HTML实体编码,把关键词转换成WAF识别不出来的形式,到了后端数据库还是会被还原成正常的SQL语句。
  • 注释符混用:用/*...*/注释符把关键词拆开,比如sel/*abc*/ect,或者用--、#、%23这些不同的注释符,绕过对--的拦截。
  • 等价函数替换:比如把sleep()换成benchmark(1000000,sha1('test')),把and换成&&,把or换成||,功能一样,但WAF匹配不到原来的关键词。
  • 特殊符号混用:用制表符%09、换行符%0A、回车符%0D代替空格,比如select%0A*%0Afrom%0Ausers,很多WAF会把空格当成关键词分隔符,换成其他空白符就匹配不到了。

三、其他特殊注入方式

这些是常规注入之外,针对特殊场景的注入方法:

  • 加解密注入:前端提交的参数是加密过的,比如密码用了MD5加密,或者参数用了AES加密,后端会解密之后再拼接到SQL语句里。这种情况你得先破解前端的加密逻辑,或者找到加密算法的漏洞,构造出能解密后变成恶意SQL语句的参数。
  • JSON注入:注入点在JSON格式的请求体里,比如{"username":"admin","password":"123"},后端直接把JSON里的字段拼接到SQL里。这种情况你要构造符合JSON格式的恶意语句,比如{"username":"admin' or 1=1 --","password":"123"},还要注意JSON的转义规则,比如引号、斜杠这些特殊字符。
  • LDAP注入:针对LDAP目录服务的注入,逻辑和SQL注入类似,都是构造恶意的查询条件,但语法不一样,用的是*、()这些特殊符号来绕过过滤或者执行恶意查询,常见于企业内部的用户认证系统。
  • 二次注入:恶意的SQL语句第一次提交的时候,后端做了过滤,被当成普通数据存到了数据库里;但后续的业务逻辑里,后端会直接把数据库里的这个数据拼接到SQL语句里执行,这时候恶意语句就被触发了。比如你注册了一个用户名是admin' --,第一次注册的时候被过滤了,但后台修改用户权限的时候,直接把用户名拼进SQL,就会把管理员的权限改掉。
  • 堆叠注入:利用数据库支持多语句执行的特性,用分号;分隔多条SQL语句,比如?id=1; drop table users;,后端执行完select * from users where id=1之后,会继续执行后面的drop table users,直接把表删掉。MySQL在开启多语句执行的时候支持这个,威力很大。

四、SQL注入防御方案

最后是怎么防注入,分开发和防护两个层面:

  • 代码层面的过滤与规范
  1. 输入验证:对参数做严格的校验,比如ID必须是数字,用户名只能包含字母和数字,长度不能超过限制,直接把不符合规则的请求拦截掉。
  2. 参数化查询(预编译语句):这是最根本的防御方法,用PreparedStatement这类预编译接口,让SQL语句和参数完全分离,参数不会被当成SQL语句执行,从根源杜绝注入。
  3. 最小权限原则:给数据库账号分配的权限越小越好,比如只给查询的权限,不给删除、修改、创建表的权限,就算被注入了,也没法做太过分的事。
  4. 错误信息脱敏:后端不要直接把数据库的报错信息返回给前端,比如You have an error in your SQL syntax,这种信息会泄露数据库的结构,给攻击者提供线索。
  • WAF产品部署: 在网站前面部署Web应用防火墙,配置规则拦截常见的注入语句、异常请求,比如拦截包含union select、sleep、drop这些关键词的请求,限制请求的频率,防止暴力猜解。
相关推荐
2301_815279522 小时前
golang如何编译iOS库_golang编译iOS库实践
jvm·数据库·python
2402_854808372 小时前
C#怎么开发CAD自定义命令_C#如何调用AutoCAD的API【教程】
jvm·数据库·python
m0_716430072 小时前
mysql乐观锁更新失败如何处理_应用层重试逻辑编写建议
jvm·数据库·python
qq_654366982 小时前
SQL嵌套查询中的变量传值_优化存储过程逻辑
jvm·数据库·python
Austindatabases2 小时前
阿里云MongoDB 部署安全吗? 多可用区怎么搞?
数据库·安全·mongodb·阿里云·云计算
m0_748920362 小时前
持久化存储如何与后端接口同步?解决本地缓存与数据库不一致痛点
jvm·数据库·python
qq_330037992 小时前
Python如何安装特定架构包_32位与64位系统兼容性处理
jvm·数据库·python
y = xⁿ2 小时前
MySQL常见八股:索引
数据库·mysql
希望永不加班2 小时前
SpringBoot 缓存一致性:缓存与数据库双写策略
数据库·spring boot·后端·缓存·oracle