SQL注入基础-理解SQL注入原理
好的,我现在需要帮用户总结一篇文章的内容,控制在100字以内,而且不需要特定的开头。首先,我得仔细阅读文章,理解它的主要观点。 文章主要讲的是SQL注入技术的学习和防范。作者强调这不是为了教人攻击,而是为了保护数据库安全。数据库在Web应用中处于核心地位,存储了用户数据、商业信息等重要信息。SQL注入攻击可以通过构造恶意SQL语句获取敏感数据。 接下来,文章解释了SQL注入是如何产生的,通常是因为服务端代码将用户输入直接拼接到SQL语句中,导致攻击者可以注入自己的代码。常见的例子是登录页面的漏洞,攻击者通过输入特定字符来改变查询逻辑。 文章还提到如何防范SQL注入,比如使用参数化查询、避免直接拼接SQL语句,并建议通过本地数据库进行练习和测试。 总结一下,文章的核心内容是:学习SQL注入技术是为了更好地防御它,理解数据库的重要性,并掌握防范方法。 </think> 文章探讨了SQL注入技术的学习与防范方法。通过理解数据库在Web应用中的核心地位和常见注入原理(如拼接用户输入),揭示了如何通过构造恶意SQL语句获取敏感数据。同时强调了防御措施的重要性,并建议通过本地数据库进行练习和测试以提高安全意识。 2026-1-20 09:27:24 Author: www.freebuf.com(查看原文) 阅读量:0 收藏

说明

该文中使用的数据库为本地测试数据库,数据内容无任何实际意义!

引言

学习SQL注入技术,不是为了成为攻击者,而是为了理解:在这个数据即权力的时代,保护数据库的安全,就是在保护数字世界的基石。每一次的防止注入攻击,你可能保护的是某个人的隐私、某个家庭的财务安全、某个企业的商业未来。这是技术人员的职业责任,也是数字公民的基本伦理。

数据库的核心地位

为了理解SQL注入的重要性,首先需要明白现代Web应用如何运作

用户浏览器 → Web服务器 → 应用程序 → 数据库
    ↑           ↑           ↑          ↑
   界面展示    逻辑处理    业务规则   数据核心

数据库处于整个架构的最底层,却是整个web应用的核心。应用程序只是数据库数据的前台展示,比如常见的个人资料,账户余额等皆来自数据库数据。

你的应用程序不是在与用户交互,而是用户提交的数据与你的数据库进行交互的过程。每一次交互都是一次数据库sql语句执行的过程,都是一次信任与危机共存的过程。

什么是数据库?

一个典型的商业应用数据库中通常包含:

用户数据层,商业数据层,系统控制层:比如用户的账号密码,交易数据,管理员的权限配置等等。

我们通常通过前端访问容易接触的都是登录过程,比如新安装一个app,或者打开一个网页需要输入用户名密码,或者注册,这些数据就需要在服务器上存储,一般存储的位置就是数据库。所以只需要完成数据库的注入攻击,即可获取所有用户的数据信息,将数据变为实际的经济价值。

常见的关系型数据库有:MySQL‌,Oracle‌,‌Microsoft SQL Server‌,PostgreSQL‌,SQLite‌等等国产数据库(TiDB‌,达梦,openGauss‌)等等

比如如下mysql数据库使用数据库工具打开之后的UI界面:

1768361200_69670cf0af950534a386b.png!small?1768361200940

非关系型数据库:MongoDB‌,Redis‌,Cassandra‌等

SQL注入主要针对关系型数据库,因为其攻击原理基于SQL语言的语法,而SQL是关系型数据库的标准查询语言。关系型数据库如MySQL、Oracle、SQL Server等均使用SQL进行数据操作,因此易成为注入目标。非关系型数据库(如NoSQL)虽然也有注入风险,但其数据模型和查询方式与SQL不同,注入方法和关系型数据库存在差异。

基础-SQL语言语法

SQL是一种声明式编程语言,这与过程式语言(如Python、Java)有本质区别,它是专门操作数据库的一种语言格式。与其他语言一样,它的执行也是具有优先级的,比如and优先级高于or。

声明式:告诉数据库"我想要什么",比如:select name from employee :查询name(名字)列的内容从表employee表中如下:得到查询结果

1768369209_69672c391ea4b7e1e3b5d.png!small?1768369209448

其不指定具体执行步骤,由数据库优化器决定如何执行。

在操作数据库的过程中,我们用的最多的基本上都是增删改查即(IDUS)‌

增(Insert)‌:往数据库里添加新数据

语法规则:INSERT INTO <表名> [(<列列表>)] VALUES (<值列表>) ;

比如:

1768369329_69672cb11aeb6b464bee7.png!small?1768369329480

‌删(Delete)‌:删除指定的数据

语法规则:DELETE FROM <表名> [WHERE <条件>];

这个较为简单,自行了解

‌改(Update)‌:修改已有数据

语法规则:UPDATE <表名> SET <列名> = <表达式> [, ...] [WHERE <条件>];

比如修改上面的价格:

1768369352_69672cc852e73c2a270fd.png!small?1768369353118

查(Select)‌:查询数据库中的现有的内容

其中查询应该是用的最多的,SQL查询语句的结构遵循‌SELECT 列表名 FROM 表名 WHERE条件 的基本框架

  • SELECT‌:指定要查询的列(或使用*表示所有列)。
  • FROM‌:定义数据来源的表名。
  • WHERE‌:设置筛选条件,仅保留满足条件的行。

比如最简单的查询语句构成:select name from employee where id = 2,不管多复杂的查询也都遵循这样的规则1768369421_69672d0da9a9b408581ce.png!small?1768369421958

以上为直接通过数据库工具对数据库进行的操作,在用户访问web应用的时候,其对数据库中的数据访问其实也是通过sql语句进行操作的。但这漏洞是如何产生的呢?

SQL注入产生的原因

我们通过web服务器的代码来看,比如登录过程存在漏洞的代码可能是下面这样的:

服务端post请求得到用户的username和password

1768369525_69672d7509c8ac897009f.png!small?1768369525212

然后通过拼接sql字符串(将用户post请求的数据拼接到字符串中),然后将该sql字符串当作数据库的SQL语言给mysql执行。

1768369556_69672d9432633f15ebaa3.png!small?1768369557386

在这个数据库中的数据如下:

1768369582_69672daeb0365d91535cd.png!small?1768369582920

比如这个示例中的我们启动这个项目:

1768369596_69672dbcba658883c09ef.png!small?1768369596823

然后输入正常的用户名,密码得到的结果是这样的:

1768369610_69672dca2f12c019fcc02.png!small?1768369610412

相当于直接在mysql中执行了SELECT * FROM users WHERE user = 'test' AND pass = 'test' 这个语句如下图:结果一致。

1768369630_69672dde5933dfce79f08.png!small?1768369630553

当然这是假设用户按照开发的预期输入的流程,但是如果用户不按照这个预期输入内容呢?

String sql = "SELECT * FROM users WHERE user = '" + username +
        "' AND pass = '" + password + "'";

从源码中可以看到,用户的输入会被拼接到sql中相当于是这样服务端的mysql数据库将会执行这条语句:SELECT * FROM users WHERE user = '用户输入' AND pass = '用户输入';那么如果用户手滑了输入了一个单引号'呢?

1768369692_69672e1c1f2679cb6e5ce.png!small?1768369692243

这样就会导致SQL执行的语法错误,无法正确识别这行语句而报错,通常这也是报错注入的一种判断方法

那么要让语句正常执行怎么做,当然是需要根据SQL语言的语法规则,让其语法正确了,让其满足SQL语言的语法规则。可以看到是多了一个'单引号。那么加一个单引号就行了,比如手滑输入2个单引号,果然会执行,不会报错,但是无法查询到结果了因为不存在user=test'的内容(在SQL中2个单引号会被解释成一个单引号内容)

1768370065_69672f916dfcc362c269e.png!small?1768370065633

SQL中2个单引号会被解释成一个单引号内容

1768370111_69672fbf20eb855aef764.png!small?1768370111247

因为在SQL 中,单引号用于表示字符串字面量:字符串以单引号开始:'同时字符串以单引号结束:',如果想在字符串中包含单引号字符,需要使用两个单引号进行转义:'',所以在SQL语句中,单引号总是成对出现的

上面查询的实际是user= test' 的内容,数据库中当然没有这个数据,所以返回空未匹配到用户数据。所以SQL注入成功的关键其实就是如何闭合SQL查询语句并让其正确执行后面的语句,而后面的语句是我们可控的。

仅仅是这样肯定无法达到我们想要的目的,我们的目的是注入SQL语句,执行一些非预期的动作,并能返回有意义的或者有价值的内容。

比如这样:

1768370291_69673073484c360c9072d.png!small?1768370291438

输入单引号,保证语法正确,但密码未知,需要同时保证执行结果为真。所以如下:SQL语句可分成3段:第一段:select * from users where user = 'test'  。第二段:'' = ''   第三段: pass = 'asdfadf' ,当执行第一段时,会查询到test用户的内容,由于and执行的优先级比or高,所以会先执行'' = ''  and pass = 'asdfadf'  得到pass = 'asdfadf' ,最后组合到一起实际执行结果是SELECT * FROM users WHERE user = 'test' OR pass = 'asdfadf',最终返回所有test用户名的信息。

1768370316_6967308c2028afb19406a.png!small?1768370316319

这样就达到了在不知道密码的情况下,登录成功。也就是所谓的万能密码。并非必须是 1=1 为万能密码,其核心原理是保证语法正确,且执行结果为真--即可查询到数据,就是所谓的万能密码---保证SQL执行结果为真。

SQL注入学习

那么在没有靶场或者环境的情况下如何快速进行注入的练习或者学习呢。答案就是搭建一个数据库,直接通过SQL语句操作数据库,同时这样也可以在渗透测试的时候进行一些问题验证。

上面已经知道了SQL注入实际就是用户的输入内容带入了SQL语句中进行了执行,那么直接在数据库中输入用户的数据就可实现模拟注入的练习。

比如上面的实际执行的SQL语句为:SELECT * FROM users WHERE user = 'test' or ''='' AND pass = 'asdfadf'将其在数据库中直接执行:效果一样

1768370937_696732f913da57dd7e640.png!small?1768370937882

当我们在安全检测过程中发现存在得注入漏洞,都可以通过本地的数据库进行模拟注入。当然最主要的前提是,要对SQL语言有一定了解,服务端的查询语句大概内容可能是什么样的。通常情况下注入的方法都不止一种,还是上面的例子,比如我们通过闭合引号,保证语法不出错,同样的我们可以通过注释的方式,更直接的将语句提前终止,让其正确执行,比如使用-- 的方式。

1768371016_696733483b8f32c355042.png!small?1768371016396

其实就是SQL语言的运用,SQL运用得越是熟练,可能注入得技巧就越多

注入类型

SQL注入的分类

SQL注入的分类,有很多种方式,有的根据注入的回显的方式分为报错注入和盲注,也有根据输入类型分为字符型和数字型的,根据回显方式可分为有回显和无回显两种

根据注入点的输入数据类型分类

这个


文章来源: https://www.freebuf.com/articles/web/466580.html
如有侵权请联系:admin#unsafe.sh