怎樣利用Hibernate來防止SQL注入的方法

巴扎黑
發布: 2017-07-23 11:42:48
原創
3068 人瀏覽過

之前寫程式碼,往後台傳入一個組織好的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注入基本上已经不存在了~~~~

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

以上是怎樣利用Hibernate來防止SQL注入的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!