论坛首页 Java企业应用论坛

Java应用中的SQL注入攻击和防范

浏览 13227 次
精华帖 (0) :: 良好帖 (3) :: 新手帖 (3) :: 隐藏帖 (12)
作者 正文
   发表时间:2010-04-26  
C_J 写道
godfish 写道
这都什么年代的事情了

我们现在的项目就有,看来已经out了~~



我们项目也有啊,而且到处都是,看来也已经out了。
0 请登录后投票
   发表时间:2010-04-26  
楼主用词就不当,这哪是什么依赖注入啊,这以前就叫SQL语句注入攻击。
不要加依赖注入进去就混淆视听,当现代技术
0 请登录后投票
   发表时间:2010-04-26  
C_J 写道
    说说自己对注入的一些体会吧。
    什么叫SQL依赖注入?顾名思义,就是依赖于SQL语句的一种攻击方式,主要采用特殊字符串来处理的SQL漏洞。
    这个SQL依赖注入已经是很老的漏洞了,现在基本上DAO层的编写已经很少使用纯JDBC来写sql语句了。

    所以在没有使用framework来做DAO,而直接使用JDBC且凭凑的SQL语句的话,那么很容易产生依赖注入的漏洞,如下用户登录模块(目前手头项目中就有活生生的例子)

    突破第一个用户名的障碍
登录模块
如:
 User validUser = login.getUserInfo(user.getName());

这里的user.getName()是前台从Textfield控件中获得得值,没有做任何处理,于是再看看getUserInfo的方法,如下:
 public User getUserInfo(String userName)
    {
        User validUser = null;
        String sql = "Select * from WEB_USER where NAME='" + userName + "'";
        Database db = null;
        ResultSet rs = null;
        try {
            db = new Database("XXX");
            rs = db.execQuery(sql);   
            if (rs != null && rs.next()) {
                 validUser = new User();
                 ....
              }
            }
         }

我们看到从前台传过来的userName没有经过任何处理而直接凭凑的SQL语句,所以如果输入者精心构造的话,就可以突破第一个屏障,生成一个有效的用户对象,比如:
输入: cjcj' or '1'='1
这样的字符串输入到后台的SQL语句就为:
select * from web_user where name='cjcj' or '1'='1'
显然,这个rs肯定是结果集的。我们完成了突破第一个屏障的任务。

细心的人可能注意到,这里我们是用的execQuery,只做一个查询操作,这样并不能达到任意登录的目的,没关系,我们再看。

    突破第二层障碍   
    我们发现:

 if(retry_cnt >= 3)
            {
                login.lockUser(user);
                List errors = new ArrayList();
                ErrorObj error = new ErrorObj();
                error.setErrorMsg("登录3次失败,该用户已被锁定,请与管理员联系");
                errors.add(error);
                this.getSession().setAttribute(CTDRConstants.ERROR_ATTRIBUTES, errors);       
                this.getRequest().setAttribute("userName", user.getName());            
                
            }    

当用户3次输入密码错误的时候,就更改用户状态,用户被锁定(目前很多网站是这种机制,所以需要谨慎一点),既然需要更改用户状态,就有可能涉及到为execUpdate操作,只要有execUpdate操作,hacker们就有机会了,我们继续往下看lockUser方法;
 public void lockUser(User user)
    {
        String sql = "update WEB_USER set status=1 where NAME='" + user.getName() + "'";
        Database db = null;
        try {
            db = new Database("XXX");
            db.execUpdate(sql);
        }
    ...
    }

这里的user对象就是刚从表里select出来的第1个对象,且user.getName()也是直接从前台页面上取的,并没有重新赋值,所以这里可以构造一个拥有语法错误的SQL,让前台报错,从而找到存储用户的表名,比如
输入cjcj' select '1'='1
后台会执行:select * from web_user where name='cjcj' select '1'='1'
然后这条出错的SQL语句信息就有可能暴露在前台了,这样我们就拿到了存储用户信息的表名。

于是我构建一个重置所有密码的SQL语句,如:
输入cjcj' or 1=1;update WEB_USER set passwd='
这样导致WEB_USER所有密码都为空或者MD5的密码。

最后就可以用cjcj' or '1'='1 这个用户登录了。
但是这样做的缺点是所有用户的密码都更改了很容易被管理员发现的。应该有更好的办法,待续...

另外如果执行的SQL语句为:
 String sql = "Select * from WEB_USER where NAME='" + userName + "' and PASSWD='"+Passwd+"'";

这样就更简单了,直接构造上面的那个输入就可以任意登录了。


我们看到,这个应用有待改进的地方:
1、对输入含有'符号进行转换或者禁止;
2、update用户锁定状态时,应该把user.getName()改为:

validUser.getName()

3、使用PrepareStatement或者使用dao层框架。




0 请登录后投票
   发表时间:2010-04-26  
这个问题确实有点老,做ASP的时候经常会有这样的问题,java提供的决绝方案已经很完备,现在自己可以进行关键字的筛选
0 请登录后投票
   发表时间:2010-04-26  
''这个初学者一般都知道吧。。。
0 请登录后投票
   发表时间:2010-04-26  
SQl注入就是了,哥们还加个“依赖”。。。还控制反转呢。。。
0 请登录后投票
   发表时间:2010-04-26  
以前记得asp中常常玩点入侵...jsp这没试过....
0 请登录后投票
   发表时间:2010-04-27  
PrepareStatement是怎样解决这种问题的?是因为一个参数必须对应一个?么?一个萝卜一个坑。
0 请登录后投票
   发表时间:2010-04-27  
都是用sql预编译就没有问题了。
0 请登录后投票
   发表时间:2010-04-27  
evilseed 写道
PrepareStatement是怎样解决这种问题的?是因为一个参数必须对应一个?么?一个萝卜一个坑。

我的理解是sql的预编译是将sql的执行计划在内存中进行存储,下次执行该sql不必再次经过查询分析器计算执行计划。预编译sql先是发送sql,然后匹配参数,非预编译sql是整条sql发送出去。请大家讨论
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics