项目亮点之解决sql注入攻击

什么是sql注入攻击

所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击

什么时候最易受到sql注入攻击

当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的 字符串来传递,也会发生sql注入。sql注入可能导致攻击者使用应用程序登陆在数据库中执行命令。如果应用程序使用特权过高的帐户连接到数据库,这种问题会变得很严重。在某些表单中,用户输入的内容直接用来构造动态sql命令,或者作为存储过程的输入参数,这些表单特别容易受到sql注入的攻击。而许多 网站程序在编写时,没有对用户输入的合法性进行判断或者程序中本身的变量处理不当,使应用程序存在安全隐患。这样,用户就可以提交一段数据库查询的代码, 根据程序返回的结果,获得一些敏感的信息或者控制整个服务器,于是sql注入就发生了。

如何防止SQL注入

1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双”-“进行转换等。(这可能是前端做的)

2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。

3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

==4.==不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。

5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装

6.sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。

其中4是项目中采用的方法。

SQL注入实例详解

比如牛客网,需要输入用户名和密码,当后台核实之后,都输入正确才能登陆网站。

填好正确的用户名(x)和密码(111111)后,点击提交,将会返回给我们咨询页面。

对应的sql语句:

select * from users where username='x' and password='111111'

很明显,肯定能够成功登陆。但是,如果我们输入一个错误的用户名或密码呢?很明显,肯定登入不了吧。恩,正常情况下是如此,但是对于有SQL注入漏洞的网站来说,只要构造个特殊的“字符串”,照样能够成功登录。

比如:在用户名输入框中输入:’ or 1=1#,密码随便输入,这时候的合成后的SQL查询语句为:

select * from users where username='' or 1=1#' and password=('')

语义分析:“#”在mysql中是注释符,这样#号后面的内容将被mysql视为注释内容,这样就不会去执行了,换句话说,上面的sql语句等价:

select * from users where username='' or 1=1

因为1=1永远是都是成立的,即where子句总是为真,将该sql进一步简化之后,等价于如下select语句:

select * from users 

没错,该sql语句的作用是检索users表中的所有字段。

这样以来,表中全部用户都会输出,造成大量的用户信息泄漏。

项目中解决方法

采用的是第四种方法:不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。

注册操作

    public Map<String, Object> register(String username, String password){
        Map<String,Object> map=new HashMap<String,Object>();
        if (StringUtils.isBlank(username)){
            map.put("msgname","用户名不能为空");
            return map;
        }
        if (StringUtils.isBlank(password)){
            map.put("msgpwd","密码不能为空");
            return map;
        }
        User user=userDAO.selectByName(username);
        if(user!=null){
            map.put("msgname","用户名已被注册");
            return map;
        }
        //密码强度
        user=new User();
        user.setName(username);
        //用UUID,随机产生5个数字
        user.setSalt(UUID.randomUUID().toString().substring(0,5));
        /**
         * 这种是完全不行的,直接在数据库里传的是明文,信息可能泄露。
         */
        String head = String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000));
        user.setHeadUrl(head);
        //user.setPassword(password);
        user.setPassword(ToutiaoUtil.MD5(password+user.getSalt()));
        //写入数据库了
        userDAO.addUser(user);
        //登录
        String loginTicket=addLoginTicket(user.getId());
        map.put("ticket",loginTicket);

        return map;
    }

源码可以看到:

没有直接对输入的密码直接做MD5的加密操作(因为有的工具可以解密通过MD5加密的信息),而是通过UUID产生随机salt(截取了5位),通过ToutiaoUtil.MD5(password+user.getSalt())的形式对用户密码加密。这样的方法有2个好处:第一,通过对用户输入的包装,能防止sql注入攻击;第二,在数据库存储的密码不是明文的。


   转载规则


《项目亮点之解决sql注入攻击》 xuxinghua 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录
I I