Protection against SQL Injection

  • 内容
  • 评论
  • 相关

SQL 注入有很严重的后果。在阅读本文之前,请理解SQL的 DML DDL DCL TCL。依据SQL存在这四类功能,简单总结下通过sql 注入可以完成的任务:

对数据库进行描述。通过结构化描述查询指令,入侵者可以彻底了解数据库结构。虽然国际标准对相关的指令没有进行规划,但是每个数据库都有自己的自描述指令。客户端连接服务器端实际上是利用自解释命令查询数据库结构的。而SQL文件本身就是利用meta信息自描述、自解释,直接得到SQL存储文件一样可以掌握数据库结构。
Backtrack上运行的SQLMap是分析mysql数据结构的成熟工具。

类似的,可以直接毁坏数据库数据。例如使用DDL的Drop指令,DML的Delete指令。这种情况下,如果被渗透方依赖信息系统、没有备份或application firewall等中间件进行保护,他们就直接可以关门了。

当然最著名的是“脱库”,即database dump。使用select语句就可以进行dump。EMC的RSA机构因为bbs dump和社工的双重攻击(当然离不开爆破),各服务器的管理密码、以及RSA的根证书都被匿名组织盗取。美国数家银行、电商也因为保护不当,用户信用卡资料被dump出来,而被直接罚款到关门。这些都不是虚构的故事。
可能有人想起上个时代伊朗伪造CA根证书的故事,不过那是个假消息;伊朗历史上发生的伪造CA和银行证书的故事,是典型的碰撞型爆破、DNS污染、中间人攻击。我国较为出名的案例恐怕是CSDN、天涯被脱库。

最严重的结果就是通过注入、利用shell直接控制主机。不过当下这是较为次要的隐患。

最恐怖的非修改数据莫属。注入可以完成persistent xss。bbs上通过注入,使管理员收到persistent xss的短消息,办坏事和找背黑锅的双重目的就都达到了。这种情况下除非在系统中存在法证调查机制(因为成本和管理上的投入,一般企业来说都没有),利用persistent xss 完成的入侵几乎不可找到一丝痕迹。

最难调查怕是注入后完成APT。APT各种各样,无法细说。经验上,apt利用漏洞、社工、管理体制缺陷、各种获得的权限,可以达到难以想象的目的。国内某门户,S大,多次被入侵和dump的故事不过是冰山一角;它提供的企业邮局的帐号hash被dump之后导致某大型国企遭殃,匿名组织结合了爆破、木马等手段,然后根据email内容里的vpn和密码信息完成对改企业的入侵,最终国家形象受损。

Sql 注入危害之大,还需要更详细说明的读者可以放弃阅读本文。

本文也完全不会介绍如何完成SQL Injection。法律上要求太多,而我不想死。

解释SQL Injection其实不困难:

SQL Injection 重新构造了前端接口(例如网页)的递交内容,从而在数据库平台上构造了新SQL查询语句,使新构造的查询语句不受预期的限制、也可以构造出额外的查询语句。

粗略的看,SQL 注入往往是下面两种情况:

Select [items] from [tables] where [conditions] or 1=1 其他ddl的注入就不演示了

[预期完成的SQL语句]+注入后的语句 (通常发生在Microsoft SQL Server ,mysql等服务器不支持单行多查询指令)

这里面技巧很多。抱歉我不享受豁免权,不能继续演示。有兴趣的读者可以去翻阅国际公开的数据库cxx什么的。

虽然翻阅国际数据库,最常见的SQL Injection都在开源项目上,例如wordpress和phpbbs等等,但是未经仔细检查过的独立开发程序往往存在更多的隐患。如何防范SQL Injection呢?

A.外因是条件,内因是根源。在发布、更新任何信息系统之前,我强烈推荐进行白盒子检测。通过对(factor)代码的控制,达到控制(effect)程序安全性。续而,从早干涉风险比晚处理后果强的角度看,应在软件开发的管理体系上实现Security Development Lifecycle。从安全实效性看,更应该定期进行代码审查。
就这样笼统的一说吧,具体理论情况与国情不符合--开发管理、问责等等制度上存在效率与安全的冲突,人事上也存在成本、考核等等问题,细说起来会争论很多话题。我国现阶段对个人隐私保护等等都不存在法律要求的情况下,要求企业投入资金为免费服务、低价格服务实现中等程度的安全--对此前景我不是十分乐观。这种服务还是外包比较符合国情。

B.运维上,尽可能的实现服务器功能最小化、尽可能应用application firewall。这两点无疑又是成本问题。即使经验上看,这是对注入防范的最低限度要求,不过各类企业又有人员能力不足、习惯外包、成本有限、不想担当责任的现实局限性。只有等待法律施压。

C.从法律取证的角度讲,如果有必要则需要做各种 数据库和程序的 hook,实现证据的取证、转移、保管。这方面完全就是logging management。我就业这么多年,就没发现有刻意实现logging的开发vendor 、也没发现过有注重logging management的同行。这方面较为悲观吧。

开发方面需要注意步步为营:

D.充分利用视图而避免原始表操作、彻底分离读写帐号。不怕每个页面调用多个帐号就怕一个帐号包揽全部功能。

早期我注意过这个问题,即多数系统使用单帐号的db connection脚本 使用同样的权限访问数据库到底会带来什么问题?

D.1 毫无疑问有安全隐患。登陆检查、查询、写操作都用同一个权限,dump出密码hash岂不是理所当然?人员的思维是自然思维,做的用户表格也是自然属性表格。把登陆校验、修改个人信息、改密码用不同的视图和表格去做,不同脚本配置上不同的权限进行连接,到底有什么不可以的?毫无疑问是思维障碍大于技术障碍。

D.2 另外一个被忽视的就是性能问题。数据库串行查询和并行查询存在性能、锁、一致性等问题。视图操作、分离帐号可以大大降低laggy。基于存储过程和视图表,配置为不同的权限,因为查询频率远远大于写频率,这也很大幅度上降低了锁和一致性的问题。

那么此时我们再看一个操作页面,分离登陆检测、按照功能分配为r(rw)、帐户信息修改的帐号,在大规模联合查询的时候就会提高效率、安全性。至少配合后面的手段,注入的成功概率远远降低。

E.严重关注存储过程与动态查询(dynamic sql query)语句。

E.1 数据库互动应当由存储过程实现。即通过传导不同的parameter后, 调用存储过程。在流行的dot net技术中,参数调用的存储过程里,语句会自动在数据库后台为单引号替换为双引号,使得注入语句不得执行。当然这主要有效对象还是Dotnet。
例如select * from dbo.sysjobs where id='testaccount";delete from others'; 注意这里的双引号部分:如果注入没有设置单引号,则新构造的语句完全当作where从句的一部分;如果注入语句有单引号则自动转义为双引号。就是说在Dot Net中,使用存储过程相当安全。
其他linux平台方面这种保护不怎么见效,linux脚本中更多要利用正则表达式、转译检测。

E.2 sql提供了dynamic sql (dsq)功能,不过那不是安全亮点、绝对是安全弱点。E.1中提到的存储过程应当最大可能的避免使用动态sql语句,应尽可能的使用视图(视图权限也要控制)和参数传递。

E.3 应用程序不应有访问E.2提到的dsq子对象(或视图)的权限

E.4 应用程序对返回数组进行数组检查,这包括类型和结构检查(构造新语句)、返回量(dump)的检查,而不应当直接使用返回数组进行输出,直接创建临时表也不是什么好习惯。

E.5 加倍小心Dynamic Sql query。虽然我的习惯是建立基本表、视图、存储过程,然后分配权限控制具体对象。但是更多的人就喜欢在语句中直接使用联合查询,构成新的安全隐患。这时需要注意的技巧是类型强制转换。

例如dot net中,参考下列两个存储过程语句的区别:

exec (@query) --来自应用层传递的注入,仍然可能在where后执行;存储过程中调用动态查询,不能起到保护作用
exec sp_executesql @query, ' @param VarChar(20)', @param=@param --继续利用类型转换带来的转义,英文是Parameterize

F 干掉系统中的多余功能。

例如xp_cmdshell 这个曾经称作“恶中之魔”的东西,xp_startmail xp_makewebtask sp_send_dbmail xp_sendmail 外泄资料的东西。不过升级sql服务器时很可能因为缺失这些功能而失败。但是没有无瑕之玉。怎么说?这些功能都存在dll里,而且删除之后给个经验丰富的渗透人员还能恢复。把DLL删除掉很多正常功能也就不可用了。

目前可以找到的方法还是控制SQL Server数据库的权限,某些决不会给程序登陆的高权限帐号才有权限访问这些功能。

G 实际上还有较为冷门的防御法。例如对递交的内容替换原音字母,进行des加密、直接索引+utf8->zlib压缩等等。不过那些方法是前端应用层防护,在多数情况下数据也需要挖掘和搜索,并不是十分的适合多数情况应用。直接替换法也有被攻破的情况。理论上,前端过滤可能发生在前端被解释(app-sql之间被转义等)、前端存在控制方法也就存在方法外泄被绕过甚至利用的可能。这里就提一下吧,仅供参考。

H 注意所有错误的处理机制。利用内部函数发生错误,这种注入的名称是“标注注入攻击”即Standard SQL Injection Attack。这个名字已经介绍了SQL出错是多么严重的问题。每个数据库的错误,都应该被单独摘出来生成不依赖数据库的错误提示页面。在各种语言环境中,注入蓄意的错误sql脚本毫无疑问可以探测SQL Injection 保护的防护点。例如,蓄意插入数字1除以0、利用Transcation SQL的特性进行计算;实时的错误返回页面,已经告诉渗透员很多信息了。注入sql可以处理的函数主要有:
计算函数、文件函数(mysql)、邮件函数、字符串处理函数、系统shell函数 等

本文管理手段介绍了A、B、C、技术手段分为D、E、F、G、H,字母排列顺序就是作者眼中的优先级顺序。

版权声明:欢迎在标注原文链接或IDF实验室的前提下转发,本文是我辛苦写的。

感谢:感谢IDF实验室“代码”,他与我电话交流脚本安全,让我放弃了大衣下的懒字,翻了很多DOT NET和SQL Server的书。

声明:我自己也不认为本文是best practice,如有任何意见欢迎交流。
2013-Jun-09 被推荐看了OWASP的文章之后,发现本文所有内容竟然就是OWASP推荐的方法;既然是安全研究组织的推荐手段,好像目前就只能这样了。https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet

参考链接:
https://www.owasp.org/index.php/Testing_for_Oracle
https://www.owasp.org/index.php/Testing_for_SQL_Server
https://www.owasp.org/index.php/Testing_for_MySQL
www.databasesecurity.com

IDF实验室 Archer

2013年6月9日
修订历史

2013年6月8日 发布第一版

2013年6月9日 增加H部分及OWASP参考

(全文完)

评论

2条评论
  1. Budi

    Just what the doctor oredred, thankity you!