简介
SQL注入(英语:SQL injection
),也称SQLI或SQL注码,是发生于应用程序与数据库层的安全漏洞。简而言之,是在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了字符检查,那么这些注入进去的恶意指令就会被数据库服务器误认为是正常的SQL指令而执行,因此遭到破坏或是入侵。
产生原因
SQL注入漏洞产生的原因是网站应用程序在编写时未对用户提交至服务器的数据进行合法性校验(类型、长度、业务参数合法性、敏感字符等),同时没有对用户输入数据进行有效地特殊字符过滤,使得用户的输入直接带入数据库执行,超出了SQL语句原来设计的预期结果,导致了SQL注入漏洞。
注入举例
以下代码为模拟web应用程序进行登录操作。若登录成功,则返回success,失败则返回fail
<?php
$conn = mysqli_connect($servername, $username, $password, $dbname);
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$username = @$_POST['username'];
$password = @$_POST['password'];
$sql = "select * from users where username = '$username' and password='$password';";
$rs = mysqli_query($conn,$sql);
if($rs->fetch_row()){
echo "success";
}else{
echo "fail";
}
?>
用户名username
和密码password
均来自于用户的直接传入,无任何过滤,后直接拼接到SQL语句中。
正常用户登录时,sql语句如下:
select * from users where username = 'admin' and password='password'
攻击者尝试登陆,输入用户名admin' or '1' = '1
,输入密码123
,因为是直接拼接,所以构造出的sql语句如下:
select * from users where username = 'admin' or '1' = '1' and password='123'
此时因为sql语句中存在or '1'='1'
,所以永为真,将会查询出所有的结果,也就会登录成功返回success。(这也是常说的万能密码之一)
应用场景
SQL注入漏洞可能出现在一切与数据库交互的地方,常见举例如下(主要还是存在于增删改查四个字上):
简而言之:所有和数据库交互的点均可能存在SQL注入
关键字 | 功能举例 |
---|---|
增 | 注册新用户、创建订单、添加文章…… |
删 | 删除用户、删除订单…… |
改 | 修改订单、更新用户信息…… |
查 | 查询信息、筛选订单、搜索文章…… |
常见数据库
数据库包括关系型数据库和非关系型数据库,这两类数据库最主要的区别如下表所示
关系型数据库 | 非关系型数据库 | |
---|---|---|
特性 | 1、采用了关系模型来组织数据的数据库 2、事务的一致性 3、关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织 |
1、使用键值对存储数据; 2、分布式; 3、一般不支持ACID特性; 4、非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合 |
优点 | 1、容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解; 2、使用方便:通用的SQL语言使得操作关系型数据库非常方便; 3、易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率; 4、支持SQL,可用于复杂的查询 |
1、无需经过sql层的解析, 2、读写性能很高;基于键值对,数据没有耦合性,容易扩展; 3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型 |
缺点 | 1、为了维护一致性所付出的巨大代价就是其读写性能比较差; 2、固定的表结构; 3、高并发读写需求; 4、海量数据的高效率读写; |
1、不提供sql支持,学习和使用成本较高; 2、无事务处理,附加功能bi和报表等支持也不好 |
常见的关系型数据库和非关系型数据库有如下几种,本章主要讨论关系型数据库的注入问题
关系型数据库
- MySQL
- Oracle
- PostgreSQL
- MSSQL
- DB2
- Access
非关系型数据库
- MongoDB
- Redis
- MemcacheDB
- InfluxDB
- Hbase
漏洞危害
- 获取数据库访问权限,甚至获得DBA权限,从而获取数据库中的所有数据,造成信息泄漏;(可获取数据)
- 对数据库的数据进行增加、删除、修改操作,例如删除数据库中重要数据的表(可进行增删改操作)
- 通过构造特殊的数据库语句,可操作数据库进入后台或者插入木马,以获取整个网站和数据库的控制权限,篡改网页,发布不良信息等;(可获取网站权限)
- 获取服务器最高权限,远程控制服务器,甚至导致局域网(内网)被入侵;(可获取服务器权限)
通用修复建议
代码层面
输入过滤
- 严格控制输入数据的类型;如通过id获取用户信息时,仅允许传入的id为整型
- 严格控制输入数据的长度;如限制用户名长度应小于20
- 输入合法性判断;禁止出现一些特殊字符或关键词,如
'
,"
,\
,<
,>
,&
,*
,;
,#
,select
,from
,where
,sub
,if
,union
,sleep
,and
,or
等 - 对所有可能的输入点进行判断检测,如UA、IP、Cookie等
预编译SQL语句(参数化查询)
参数化查询是一种查询类型,其中占位符用于填充参数,参数值在执行时提供。原理是采用了预编译的方法,先将SQL语句中可被用户控制的参数集进行编译,生成对应的临时变量集,再使用对应的设置方法,为临时变量集里面的元素进行赋值,赋值过程中会对传入的参数进行强制类型检查和安全检查。
所有与数据库交互的业务接口均采用参数化查询,参数化的语句使用参数而不是将用户输入变量直接嵌入到SQL语句中,参数化查询是防御SQL注入的最佳方法,比如:Java中的PreparedStatement
,PHP中的PDO
等。
数据库层面
最小权限原则
遵循最小化权限原则,严格限制网站用户的数据库的操作权限,禁止将任何高权限帐户(sa,dba、root等)用于应用程序数据库访问,从而最大限度的减少注入攻击对数据库的危害。
禁用敏感函数
防止攻击者通过SQL注入获取到除数据库外的其他更高权限,如系统权限等;
比如MSSQL中,拒绝用户访问敏感的系统存储过程,如xp_dirtree
、xp_cmdshell
等。
权限控制
限制用户仅能够访问必须使用的数据库表。
统一编码
网站与数据层的编码统一,建议全部使用UTF-8编码,避免因上下层编码不一致导致一些过滤模型被绕过,比如宽字节注入等。
其他层面
- 网站应避免抛出SQL语句执行过程中的错误信息,如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断;
- 使用通用防注入系统,或者部署WAF等。
学习靶场
TIPS
- 在测试SQL注入的时候,一定要思考后端的SQL语句是如何书写的,只有判断出后端SQL语句的大概书写情况,才能知道我们可控注入点的位置,可能是
select sqli
、where id =
、order by sqli
,这样才好对症下药。 - 内容可能有遗漏,发现可以补充的再补吧,一点点的完善