注: 全文以 MySQL 数据库为例。
1、SQL注入简述
SQL注入(SQL Injection)是指,由于开发人员在编写网站的数据交互代码,也就是拼接的SQL语句时,对用户输入的参数没有做安全过滤,导致用户输入的一些不合法的查询参数被成功解析,并在数据库中执行,窃取数据库内容。
产生原因:
- 构建的SQL语句中包含了不被信任的数据,如用户输入信息等,但是又没有做安全防范。
比如某站点构建的查询语句参数是id值,一般都是传入id = 1、2、3等这类数字,但是当用户非法输入参数:id = 1 and database(),那么就有可能查询出当前的数据库名,以此类推。
SQL注入由于直接对网站的内部数据造成威胁,窃取和修改用户信息,破坏数据的机密性和完整性,因此危害极大,前些年这类漏洞比较多,但是随着各种框架的产生,和程序员本身的安全意识的提升,目前SQL注入漏洞已经很少了。
2、SQL注入分类
SQL注入的分类比较多,是从以下几个不同的角度来分类的:
参数类型、注入位置、结果反馈。
参数类型:
- 数字型:注入点的参数是整型,也就是 id = id
- 字符型:注入点的参数是字符型,也就是 id = ‘id’。(宽字节注入也属于字符型)
注入位置:
- GET注入:注入位置在URL参数中
- POST注入:注入字符在POST数据中
- Cookie注入:向Cookie字段中注入内容
- HTTP头注入:HTTP头的Referer和user-agent字段中存在注入漏洞
结果反馈:
- 基于报错:注入结果会显示在页面上
- 盲注
2.1)基于布尔的盲注
通过加入一些判断命令,如判断数据库名长度:1’ and length(database()) = 10 #,根据是否有响应来猜测判断是否正确。可以借助SUBSTR、LIMIT、ASCII等一些特殊的命令及函数进行猜测。
2.2)基于时间的盲注
在SQL语句中添加延时函数
,根据相应时间来判断是否存在SQL注入,常用的延时函数或指令有sleep、repeat等。
一些盲注常用的函数:
- if(condition,A,B):若condition返回真则执行A,假则执行B
- substr(str,A,B):字符串截取函数,截取str字符串从A位置开始,截取B个字符
- left(str,A):类似字符串截取函数,返回str字符串从左往右数的A个字符
- count(A):计算A的数目,常用与查询数据表、数据列、数据内容的条数
- len(A):计算A的长度,常用于返回数据库名、数据表名、数据列名的长度
- ascii(A):返回A的ascii码,当逐字猜解限制单引号的输入时,可以通过查询ascii码来绕过
3、SQL注入流程
SQL注入一般有以下几个步骤:
- 找出注入点,并判断是字符型还是数字型。
(使用 and 1=1 或 or 1=1,和 and 1=2 或 or 1=2) - 猜当前表的字段数
(使用 order by) - 确定显示的字段顺序
(使用联合查询 union select) - 获取当前数据库
(database()) - 获取当前表
(select table_name from information.schema.tables where table_schema=database()) - 获取字段
(select column_name from information_schema.columns where table_name=‘TableName’ ) - 得到数据
table_schema
是数据库的名称,table_name
是具体的表名,table_type
指的是表的类型
注: 一般的SQL注入就是按照这个流程,盲注也是如此,只不过所有的查询信息都通过一些构造的反馈来显示,如时延。
一些数据库常用的函数:
- user() 当前用户名
- database() 当前所用数据库
- current_user() 当前用户名(可以用来查看权限)
- version() 数据库的版本
- @@datadir 数据库的路径
- load_file() 读文件操作 into
- outfile()/into dumpfile 写文件操作
其中,特别注意:information_schema 库
information_schema是MySQL中自带的一个特别特殊的库,它存储着数据库中所有的库名、表名和字段信息以及访问权限,也就是存储数据库元数据(关于数据的数据),访问该数据库就可以得到数据库中所有信息。
因此SQL注入的关键是查询该数据库中的内容,可通过下面两个语句,查询指定数据库中的所有表名和字段:
1)select table_name from information_schema.tables;
2)select column_name from information_schema.columns;
所以,SQL注入中查询数据时,information_schema库必不可少。
4、SQL注入防范
防范SQL注入,要根据其形成原因来分析,因此可以总结为以下几个方面:
- 不构建动态SQL语句!
比起过滤、转译,能从根本预防SQL注入的方法,就是不直接使用用户的输入拼接SQL语句,而是使用参数化查询,或者是使用准备好的查询语句。
但是,这种情况下也不能忘记过滤,要对用户的输入做安全过滤。 - 严格区分用户权限和管理员权限
对普通用户的权限,尽可能做到最低,且要明确区分管理员权限和用户权限。 - 避免向用户提示数据库错误
攻击者可以利用这些报错信息,来进行渗透。
除此之外,还有一些其他的方法,如数据加密、使用Web防火墙、及时更新数据库、打补丁等,这些都是广谱防护,有效范围广。