• 使用Hibernate防止SQL注入的方法


    之前写代码,往后台传入一个组织好的String类型的Hql或者Sql语句,去执行。

    这样其实是很蠢的一种做法!!!!

    举个栗子~~

    我们模仿一下用户登录的场景:

    常见的做法是将前台获取到的用户名和密码,作为字符串动态拼接到查询语句中,然后去调用数据库查询~查询的结果不为null就代表用户存在,则登陆成功,否则登录失败!

    正常情况下用户输入账号是123456和密码123(假设是错误的密码或者说这个用户根本不存在)

    usernameString//前台输入的用户名
    passwordString//前台输入的密码
    //hql语句
    String queryString = "from User t where t.username= " + usernameString + " and  t.password="+ passwordString;
    //执行查询
    List result = session.createQuery(queryString).list();

    正常用户输入的话,sql语句被拼接成: from User t where t.username=123456  and t.password=123 ;

    这样是正常的sql语句。可以去查询数据库验证是否有此用户数据。

    但是!

     如果用户在密码输入框中输入:123  or 1=1   作为一个字符串传入后台后

    sql语句被拼接成: from User t where t.username=123456  and t.password=123 or 1=1;

    一旦加上or 1=1 那么这条sql永远成立!!!更严重的可以删除数据库中表,篡改信息,及其严重!!!

    我们来解释一下为什么会被SQL注入?

    sql注入的原因,表面上说是因为 拼接字符串,构成sql语句,没有使用 sql语句预编译,绑定变量。

    但是更深层次的原因是,将用户输入的字符串,当成了 “sql语句” 来执行。

    比如上面的 String queryString = "from User t where t.username= " + usernameString + " and t.password="+ passwordString;

    我们希望用户输入的 username和password 的值,仅仅作为一个字符串字面值,传入数据库执行。

    但是当输入了:123 or 1=1 时,其中的 or 1=1 并没有作为 where id= 的字面值,而是作为了 sql语句 来执行的。所以其本质是将用户的输入的数据,作为了命令来执行。

    SQL防御

    基本上大家都知道 采用sql语句预编译和绑定变量,是防御sql注入的最佳方法为了防止SQL注入,避免使用拼凑SQL语句的方式!!!

    实际项目中,一般我们都是采用各种的框架,比如ibatis, hibernate,mybatis等等。他们一般也默认就是sql预编译的。对于ibatis/mybatis,如果使用的是 #{name}形式的,那么就是sql预编译,使用 ${name} 就不是sql预编译的。

    参数绑定有2种办法:使用positional parameter(查询字符串中使用?)或者named parameter(查询字符串中使用:)

    hibernate支持JDBC样式的positional parameter(查询字符串中使用?),它同使用named parameter的效果一样(查询字符串中使用:)。

    使用named parameter

    usernameString//前台输入的用户名
    passwordString//前台输入的密码
    //hql语句
    String queryString = "from User t where t.username:usernameString and t.password: passwordString";
    //执行查询
    List result = session.createQuery(queryString)
                          .setString("usernameString ", usernameString )
                          .setString("passwordString", passwordString)
                          .list();            

    使用positional parameter

    usernameString//前台输入的用户名
    passwordString//前台输入的密码
    //hql语句
    String queryString = "from User t where t.username=? and t.password=?";
    //执行查询
    List result = session.createQuery(queryString)
                          .setString(0, usernameString )
                          .setString(1, passwordString)
                          .list();           

    两者比较:positional parameter可读性强不如named parameter的强,而且可维护性差,如果我们的查询稍微改变一点,将第一个参数和第二个参数改变一下位置,

    这样我们的代码中涉及到位置的地方都要修改,所以我们强烈建议使用named parameter方式进行参数绑定。

    最后,在named parameter中可能有一个参数出现多次的情况,应该怎么处理呢?

    在举个栗子~~

    我们模仿一下用户登录的场景:这次业务变换,有的网站,手机号可以作为用户名来登录,也能作为手机号本身登录。

    常见的做法是将前台获取到的用户名or手机号和密码,作为字符串动态拼接到查询语句中,然后去调用数据库查询~查询的结果不为null就代表用户存在,则登陆成功,否则登录失败!

    正常情况下用户输入账号是13812345678和密码123

    这里usernameString作为手机号又作为用户名出现了两次,怎么办呢?

    大家请看下面代码:

    usernameString//前台输入的用户名
    passwordString//前台输入的密码
    //hql语句
    String queryString = "from User t where t.username:usernameString and
    t.phone:usernameString and t.password: passwordString";
    //执行查询
    List result = session.createQuery(queryString)
                          .setString("usernameString ", usernameString )
                          .setString("passwordString", passwordString)
                          .list(); 

    在Hibernate+spring中getHibernateTemplate()返回的对象可以调用find(String queryString, Object value...Object value)来实现named parameter。比如:

    usernameString//前台输入的用户名
    passwordString//前台输入的密码
    //hql语句
    String queryString = "from User t where t.username:usernameString and t.password: passwordString";
    //执行查询
    return getHibernateTemplate().find(queryString, usernameString, passwordString);     

     PS:其实说这么多都是扯淡,因为现在真是商业项目中,没有把密码以明文的方式存入数据库的,基本上都是经过加密以后进行比对。所以不管用户输入什么都会解密成一个字符串。所以,这种SQL注入基本上已经不存在了~~~~

    所以还是建议大家在开发中,多规范一下自己的代码,让代码更加健壮!

  • 相关阅读:
    P1603 斯诺登的密码
    C++ 文件操作
    Hibernate Dialect must be explicitly set
    Dijkstra算法详解
    Php 使用 fsockopen发送http请求
    再探java基础——break和continue的用法
    Android源码的下载和编译
    ALV列、行、单元格颜色设置
    数学之路(3)-机器学习(3)-机器学习算法-欧氏距离(2)
    [poj 2926]Requirements[最远曼哈顿距离]
  • 原文地址:https://www.cnblogs.com/klslb/p/7146889.html
Copyright © 2020-2023  润新知