使用Hibernate防止SQL注入的方法

以前寫代碼,日後臺傳入一個組織好的String類型的Hql或者Sql語句,去執行。java

這樣實際上是很蠢的一種作法!!!!spring

舉個栗子~~

咱們模仿一下用戶登陸的場景:sql

常見的作法是將前臺獲取到的用戶名和密碼,做爲字符串動態拼接到查詢語句中,而後去調用數據庫查詢~查詢的結果不爲null就表明用戶存在,則登錄成功,不然登陸失敗!數據庫

正常狀況下用戶輸入帳號是123456和密碼123(假設是錯誤的密碼或者說這個用戶根本不存在)session

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 ;mybatis

這樣是正常的sql語句。能夠去查詢數據庫驗證是否有此用戶數據。框架

可是!網站

 若是用戶在密碼輸入框中輸入:123  or 1=1   做爲一個字符串傳入後臺後加密

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

一旦加上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注入基本上已經不存在了~~~~

因此仍是建議你們在開發中,多規範一下本身的代碼,讓代碼更加健壯!

相關文章
相關標籤/搜索