使用Hibernate防止SQL注入的方法
2018-06-17 23:55:26来源:未知 阅读 ()
之前写代码,往后台传入一个组织好的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注入基本上已经不存在了~~~~
所以还是建议大家在开发中,多规范一下自己的代码,让代码更加健壮!
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:MySQL手册
下一篇:mysql重置root密码
- PHP访问MySQL查询超时怎么办 2020-03-09
- MySQL中使用WHERE子句的方法 2019-10-25
- 关于laravel后台模板laravel-admin select框的使用详解 2019-10-08
- PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql 2019-09-23
- 使用 Shell 在多服务器上批量操作 2019-09-23
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash