SQL注射/SQL Injection漏洞
0x00 相关背景介绍
随着互联网web和信息技术的发展,在web后端作为存储和管理的的数据库也得到了广泛的应用,与web结合较为紧密的数据库包括Mysql,Sqlserver,Oracle,Sqllite,Db2,Access等等。 数据存储和管理作为应用的一个基本需求,在绝大多数的应用里都得到了使用,这种大面积的使用也意味着在数据库操作方面如果处理不当出现问题的可能性会很大,另外一方面由于数据库承载了应用的数据信息,如果数据库出现问题一方面可能导致敏感数据的泄露和篡改(如信用卡账户,用户密码,管理账户和密码,销售记录等等),直接导致损失和应用被攻陷,另外一方面,即使数据库中不承载较为敏感的信息,由于数据库的特殊性,数据库被攻击的话也可以直接导致应用程序崩溃及其他严重的后果。
0x01 成因
应用为了和数据库进行沟通完成必要的管理和存储工作,必须和数据库保留一种接口。目前的数据库一般都是提供api以支持管理,应用使用底层开发语言如Php,Java,asp,Python与这些api进行通讯。对于数据库的操作,目前普遍使用一种SQL语言(Structured Query Language语言,SQL语言的功能包括查询、操纵、定义和控制,是一个综合的、通用的关系数据库语言,同时又是一种高度非过程化的语言,只要求用户指出做什么而不需要指出怎么做),SQL作为字符串通过API传入给数据库,数据库将查询的结果返回,数据库自身是无法分辨传入的SQL是合法的还是不合法的,它完全信任传入的数据,如果传入的SQL语句被恶意用户控制或者篡改,将导致数据库以当前调用者的身份执行预期之外的命令并且返回结果,导致安全问题。 那么恶意用户如何才能控制传入的SQL语句呢?我们知道,既然传入的SQL是以字符串的方式传入的,这个字符串由应用生成,那么如果应用生成这个字符串的方式不对将可能导致问题,譬如考虑如下的功能:
$sql="select * from members where userid=".$_GET[userid];
$sb->query($sql);
这段代码的逻辑是根据用户请求的Userid进入数据库查询出不同的用户并且返回给用户,可以看到最终传入的字符串有一部分是根据用户的输入来控制的,一旦用户提交
poc.php?userid=1 or 1=1
最终进入程序之后传入数据库的逻辑将是
$sb->query("select * from members where userid=1 or 1=1");
用户完全可以根据传入的内容来控制整个SQL的逻辑,实现间接控制和管理数据库的目的,这种命令(SQL语句)和数据(用户提交的查询)不分开的实现方式导致了安全漏洞的产生。 由于不同的开发语言可能对api进行了不同的封装,并且各种语言内部对数据的校验会有不同的要求,譬如java和python属于变量强类型并且各种开发框架的流行导致出现SQL注射的几率较小,php属于弱类型不会对数据进行强制的验证加上过程化的程序编写思路导致出现注射的几率会较大。
0x02 攻击方式及危害
通过典型的SQL注射漏洞,黑客是可以根据所能控制的内容在SQL语句的上下文导致不同的结果的,这种不同主要体现在不同的数据库特性上和细节上。同时,后端的数据库的不同导致黑客能利用SQL语句进行的操作也并不相同,因为很多的数据库在标准的SQL之外也会实现一些自身比较特别的功能和扩展,常见的有Sqlserver的多语句查询,Mysql的高权限可以读写系统文件,Oracle经常出现的一些系统包提权漏洞。 即使一些SQL注射本身无法对数据本身进行一些高级别的危害,譬如一些数据库里可能没有存储私密信息,利用SQL查询的结果一样可能对应用造成巨大的灾难,因为应用可能将从数据库里提取的信息做一些其他的比较高危险的动作,譬如进行文件读写,这种本身无价值的数据和查询一旦被应用本身赋予较高的意义的话,可能一样导致很高的危害。 评估一个SQL注射的危害需要取决于注射点发生的SQL语句的上下文,SQL语句在应用的上下文,应用在数据库的上下文,综合考虑这些因素来评估一个SQL注射的影响,在无上述利用结果的情况下,通过web应用向数据库传递一些资源要求极高的查询将导致数据库的拒绝服务,这将是黑客可能能进行的最后的利用。
0x03 实际案例
WooYun: 新浪SAE沦陷,oauth token/安全密码全部泄露,hack任意app 由于数据库链接的权限过于集中,通过构造合适的SQL语句,恶意用户窃取当前数据库连接里所有的数据,从一个本不是特别严重的数据库查询处攻击成功到较为敏感的数据,从而实现一个安全漏洞的最大的破坏。 WooYun: 搜狐女人频道SQL注射漏洞
同样由于程序对数据过滤不严,导致用户可以控制程序处理的SQL语句,本身该查询对数据进行攻击的意义并不大,因为数据库里不包含特别敏感的信息,精心构造该SQL语句可以将取回的结果反作用于程序,利用程序对结果的处理(这里是将取回的数据进行读模板操作),将导致可以在服务器上执行命令,从而演变为一个高危险的漏洞。 0x04 修复方案 比较传统的修复方式一般认为是对输入的数据进行有效的过滤,但是由于输入的来源太过广泛,可能来自于数据库,HTTP请求,文件或者其他的数据来源,较难对所有进入的数据在各种场景下进行有效的过滤。 事实上最罪恶的不是数据,而是我们使用数据的方式,最为彻底的修复一定要查找最为彻底的根源,我们可以看到最后的根源在于对数据和指令的不分离,所以在修复的时候应该极力将数据和指令分离。目前较为提倡的,同时在各种数据库操作框架里体现的方式就是以填充模板的方式来代替传统的拼接的方式进行数据库查询,
譬如:
$SqlTemplate="select * from members where userid={userid|int}";
$sb->PreSql($SqlTemplate,$_GET['userid']);
模板里有关数据及数据自身意义的描述,PreSql方法将实现将模板和数据安全的转换为SQL语句的功能,以保障最终的安全的实现。