SQL注入分析

小P是一家公司的程序员,微胖,喜欢留着胡须渣子。

2018年的一天,刚上班,小P就被老板叫到办公室发难:“小P啊,我们的产品网站虽然还处于小范围试运行阶段,但是信息安全还是要注意。刚才我登录后台管理系统,发现我的管理员账号在昨晚凌晨1点,有登录过。去查查,什么原因。”

小P有点懵了,该网站处于试运行阶段。老板对凌晨1点的登录记录有疑问,说明老板确实没有授权其他人使用账号。小P只好通过技术手段去查找原因,不得不说,这老板真细心……

小P经过思考,认为人为的账号密码泄露不是主要原因,暂且不管,那么可能的情况就是系统出错,导致数据显示错误或者程序逻辑不正确,日志记录错误,又或者有人恶意攻击网站。先从日志记录开始查找。

在网站运行日志中,未发现任何报错信息,说明程序未产生异常。小P仔细撸了几遍代码,依然没有发现逻辑上的问题。小P想起来,刚才看日志的时候,发现了凌晨1点的管理员登录成功记录,该账号正是老板的账号(admin),小P立即到数据库中查找SQL执行记录,发现这样一条SQL:

Select * from user where name=’admin’ andpw=’’ or 1=1

把该语句拿到SQL编译器中执行,正确执行,切查询出来了管理员信息。

该SQL中的name和pw参数的值,是通过登录页面传进来的,但是并没有or 1=1这样的字符,那么这样的SQL是从哪里进来的呢?

小P打开网站后台,对着功能,仔细查找代码。果然有所发现,只需要在密码输入框中填入’’or 1=1 这样的字符,就能顺利进去后台。

原来,页面直接把用户输入的数据传给了后台程序,后台程序则直接将数据拼接成SQL,送到数据库中执行,导致管理员账户无需密码即可登录。

String name = get(‘name’);

String pw = get(‘pw’);

String sql = ‘select * from user wherename=’+name+’&pw=’+pw;

因此当攻击者将pw参数的值写为:’’or 1=1 时,这样拼接的SQL能正确执行,并返回结果给到应用,应用便允许攻击者登录。

知道原因后,小P立即撸代码,把一些特殊字符进行过滤,然后测试发布,一切OK,和老板汇报,此事已经解决。

第二天,老板又找小P发难,还是一样的事情,老板的账号被人使用了。小P彻底懵圈了,难道还有没有过滤的字符,立即去查找日志,发现,攻击者摸清了他的过滤规则,变化输入的字符,再次进去了后台。

小P想起来出差在外的老大,赶紧邮件将此事汇报给老大。不一会,老大邮件回复:这是典型的SQL注入攻击。由于WEB程序对用户输入的数据,合法性判断缺失或者不合理,攻击者可以在预先定义好的SQL中加入额外的SQL语句,以此来欺诈数据库,执行非授权的操作。

你的过滤策略虽然能阻止部分特殊语句,但不能阻止绝大部分,只要攻击者调整语句,就能适应你的过滤策略,实施攻击。因此,目前正确的做法是把SQL语句先进行预编译,然后再把参数赋值,最后执行SQL,这种做法能阻挡绝大部分的SQL注入攻击。

说到预编译,小P想起来了JAVA语言中的PreparedStatement,于是将代码进行调整:

String name = get(‘name’);

String pw = get(‘pw’);

String sql = ‘select * from user wherename=? and pw=?’;

PreparedStatement pt = conn. prepareStatement(sql);

pt.setString(1,name);

pt.setString(2,pw);

pt.executeUpdate();

这样就能做到防止SQL注入了。那原因是什么呢?爱学习的小P通过查找资料,总结了下:

其实是因为SQL语句在程序运行前已经进行了预编译,在程序运行时,第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库以参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了!

小P还去查找资料,原理很多开发框架都可以阻止SQL注入,但其原理均是预编译SQL和参数化。

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180530G0N50B00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券