我们以SQL数据库为例,了解一下数据库注入。先了解一下相关知识。将不受信任的数据作为命令或查询的一部分发送到解析器时,会产生诸如 SQL 注入OS 注入和LDAP 注入的注入缺陷,攻击者的恶意数据可以诱使解析器在没有适当授权的情况下执行非预 期命令或访问数据。
一、SQL 注入的字面意思
学习 SQL 注入首先要了解什么是 SQL,在百度百科的解释如下:结构化查询语言 (Structured Query Language) 简称 SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系 数据库系统 ;同时也是数据库脚本文件的扩展名。从解释上来看,SQL 是用来对数据库系统进行操作的结构化查询语言,数据库存储数据,SQL 就是用来告诉数据我要什么数据,我要存储什么样的数据。
关于数据库,通常分为两类,一类是 关系型数据库 ,还有一类是非关系型数据库,那么什么是关系型数据库,百度百科的解释如下: 关系数据库 ,是建立在 关系模型 基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。标准数据查询语言SQL就是一种基于关系数据库的语言,这种语言执行对关系数据库中数据的检索和操作。当前主流的关系型数据库有 Oracle、DB2、PostgreSQL、Microsoft SQL Server、Microsoft Access、MySQL、浪潮 K-DB 等。
关于 非关系型数据库 ,百度百科的解释如下:
非关系型数据库,又被称为 NoSQL (Not Only SQL ),意为不仅仅是 SQL( Structured QueryLanguage,结构化查询语言),NoSqL 描述的是大量结构化数据存储方法的集合,根据结构化方法以及应用场合的不同,主要可以将 NOSQL 分为以下几类:
1、Column-Oriented
面向检素的列式存储,其存储结构为列式结构,同于关系型数据库的行式结构,这种结构会让很多统计聚合操作更简单方便,使系统具有较高的可扩展性。这类数据库还可以适应 海量数据 的增加以及数据结构的变化,这个特点与 云计算 所需的相关需求是相符合的,比如 GoogleAppengine 的 BigTable 以及相同设计理念的 Hadoop 子系统HaBase 就是这类的典州代表。需要特别指出的是,Big Table 特别适用于 MapReduce 处理,这对于云计算的发展有很高的适应性。
2、Key-Value。
面向高性能并发读/写的 缓存 存储,其结构类似于数据结构中的 Hash 表,每个 Key 分别对应一个 Value,能够提供非常快的查询速度、大数据存放量和高并发操作,非常适合通过主键对数据进行查询和修改等操作。Key-Value 数据库的主要特点是具有极高的并发读/写性能,非常适作为缓存系统使用。MemcacheDB、BerkeleyDB、Redis、Flare 就是 Key-Value 数据库的代表。
3、Document-Oriented。
面向海量数据访问的文档存储,这类存储的结构与 Key-Value 非常相似,也是每个 Key 别对应一个 Value,但是这个 Value 主要以 JSOn(JavaSriptObjectNotations) 或者 XML 等格式的文档来进行存储。这种存储方式可以很方便地被面向对象的语言所使用。这类数据库可在海量的数据中快速查询数据,典型代表为 MongoDB、CouchDB 等。
在了解完 SQL 之后,我们来理解一下什么是注入:
注入:顾名思义就是插入的意思,在这里的意思就是在正常的 SQL 语句中,插入我们构造的语句,在获取正常结果的情况,执行我们构造的 SQL 语句获取额外的数据,导致数据泄漏。
二、通过实例了解 SQL 注入
在学习 SQL 注入实例之前,大家要先明白一些 http 协议的基础,比如如何通过 GET/POST/COOKIE 的方式向页面提交参数数据,这里就不多说了,下面就以大家最熟悉的 php+mysql 作为例子来解释 SQL 注入的过程。
我们就以最常见的 GET 来作为理解的对象,假设有一个查看个人信息的页面,链接如下:
懂 http 协议的朋友肯定知道上面链接中哪个是提交的参数,是我们可以控制的并任意修改的,在浏览器请求这个链接的时候,参数 id 的值会被服务端,通过函数$_GET[‘id’] 获取,正常的 sql 语句如下:
select * from users where id = $_GET[‘id’];
提交之前的链接后,id 的值 1 就会被带入上面的查询语句,如下:
select * from users where id = 1;
这样做也没什么不妥,功能完全实现了,但是有了这群不按常理出牌的人之后,就不安全了,平民老百姓没人去修改 url 上的参数,大部分根本不理解这个 url 是如何构成的,所以世界本来是安全的,有了这些搞安全的,世界就不安全了。
当我们把 url 改成下面这样:
union select database(
我们的参数 id 的值就变成了 -1 union select database()这时的数据库查询语句就变成了:
select * from users where id = -1 union select database()
懂数据的肯定知道上面的语句的结果,返回的结果是原本程序做不到的,这就实现了 SQL 注入。
关于 SQL 注入有两个方面,一个是 SQL 注入漏洞:
通过简单的测试,测试这个参数存在 SQL 注入利用的可能就可以说这里存在 SQL 注入漏洞
还有一个就是 SQL 注入攻击:
在确定存在 SQL 注入漏洞的情况下,通过手工或者工具的方式,将数据库中的敏感信息 dump 出来或者利用数据库的特定获取系统的权限,这是一个利用的过程,在如今法律如此严格的情况下,在做渗透测试的时候,切记不要做这一步。
三、SQL 注入如何防御
从上面的例子可以看出,我们的参数是通过拼接 字符串 的方式进行的,在写 php 代码的时候,通过 $_GET[‘id’] 获取到参数值之后直接拼接到了 SQL 查询语句的后面,不过你提交的参数是什么都被当作 SQL 语句来执行了,那么我们如何解决这个问题呢?
如今为了解决 SQL 注入的问题,从一开始的过滤到现在使用的数据库操作的库,使用参数化查询的方式,将用户输入或者参数的值全部当作字符串来处理,不管你输入的是什么,在 SQL 查询语句中,你就是一个字符串,这样你构造的查询语句就被当作字符串来处理了,语句不被执行也就不会存在 SQL 注入的问题了。
俗话说,只要是用户输入的都不可以信任,一个系统用户可控的参数千千万,只要有一个地方疏忽,那你之前做的一切就前功尽弃了,扩展一下,不仅仅是用户输入的不可信,只要是数据可以伪造的都不可信,比如 http 协议里的 Referer/user-agent 等。
总结: 说了这么多废话,这个文章的目的就是让一些没什么基础的人了解一下大家常说的 SQL 注入相关的东西,从上面的描述可以看出,想要学习 SQL 注入,最起码的 http 协议是要学的,不同数据的查询语句以及数据库特性也是需要了解的,一个网站的数据处理流程也是需要了解的,在有基础的情况下,了解 SQL 注入的原理,然后就是进阶阶段。