怎么使用Hibernate來(lái)防范SQL注入的方法
發(fā)表時(shí)間:2023-07-27 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]之前寫代碼,往后臺(tái)傳入一個(gè)組織好的String類型的Hql或者Sql語(yǔ)句,去執(zhí)行。這樣其實(shí)是很蠢的一種做法。。!舉個(gè)栗子~~我們模仿一下用戶登錄的場(chǎng)景:常見的做法是將前臺(tái)獲取到的用戶名和密碼,作為...
之前寫代碼,往后臺(tái)傳入一個(gè)組織好的String類型的Hql或者Sql語(yǔ)句,去執(zhí)行。這樣其實(shí)是很蠢的一種做法!。!
舉個(gè)栗子~~
我們模仿一下用戶登錄的場(chǎng)景:
常見的做法是將前臺(tái)獲取到的用戶名和密碼,作為字符串動(dòng)態(tài)拼接到查詢語(yǔ)句中,然后去調(diào)用數(shù)據(jù)庫(kù)查詢~查詢的結(jié)果不為null就代表用戶存在,則登陸成功,否則登錄失。
正常情況下用戶輸入賬號(hào)是123456和密碼123(假設(shè)是錯(cuò)誤的密碼或者說(shuō)這個(gè)用戶根本不存在)
usernameString//前臺(tái)輸入的用戶名passwordString//前臺(tái)輸入的密碼//hql語(yǔ)句String queryString = "from User t where t.username= " + usernameString + " and t.password="+ passwordString;//執(zhí)行查詢List result = session.createQuery(queryString).list();
正常用戶輸入的話,sql語(yǔ)句被拼接成: from User t where t.username=123456 and t.password=123 ;
這樣是正常的sql語(yǔ)句。可以去查詢數(shù)據(jù)庫(kù)驗(yàn)證是否有此用戶數(shù)據(jù)。
但是!
如果用戶在密碼輸入框中輸入:123 or 1=1 作為一個(gè)字符串傳入后臺(tái)后
sql語(yǔ)句被拼接成: from User t where t.username=123456 and t.password=123 or 1=1;
一旦加上or 1=1 那么這條sql永遠(yuǎn)成立。!更嚴(yán)重的可以刪除數(shù)據(jù)庫(kù)中表,篡改信息,及其嚴(yán)重。!
我們來(lái)解釋一下為什么會(huì)被SQL注入?
sql注入的原因,表面上說(shuō)是因?yàn)?拼接字符串,構(gòu)成sql語(yǔ)句,沒有使用 sql語(yǔ)句預(yù)編譯,綁定變量。
但是更深層次的原因是,將用戶輸入的字符串,當(dāng)成了 “sql語(yǔ)句” 來(lái)執(zhí)行。
比如上面的 String queryString = "from User t where t.username= " + usernameString + " and t.password="+ passwordString;
我們希望用戶輸入的 username和password 的值,僅僅作為一個(gè)字符串字面值,傳入數(shù)據(jù)庫(kù)執(zhí)行。
但是當(dāng)輸入了:123 or 1=1 時(shí),其中的 or 1=1 并沒有作為 where id= 的字面值,而是作為了 sql語(yǔ)句 來(lái)執(zhí)行的。所以其本質(zhì)是將用戶的輸入的數(shù)據(jù),作為了命令來(lái)執(zhí)行。
SQL防御
基本上大家都知道 采用sql語(yǔ)句預(yù)編譯和綁定變量,是防御sql注入的最佳方法。為了防止SQL注入,避免使用拼湊SQL語(yǔ)句的方式!!
實(shí)際項(xiàng)目中,一般我們都是采用各種的框架,比如ibatis, hibernate,mybatis等等。他們一般也默認(rèn)就是sql預(yù)編譯的。對(duì)于ibatis/mybatis,如果使用的是 #{name}形式的,那么就是sql預(yù)編譯,使用 ${name} 就不是sql預(yù)編譯的。
參數(shù)綁定有2種辦法:使用positional parameter(查詢字符串中使用?)或者named parameter(查詢字符串中使用:)。
hibernate支持JDBC樣式的positional parameter(查詢字符串中使用?),它同使用named parameter的效果一樣(查詢字符串中使用:)。
使用named parameter
usernameString//前臺(tái)輸入的用戶名passwordString//前臺(tái)輸入的密碼//hql語(yǔ)句String queryString = "from User t where t.username:usernameString and t.password: passwordString";//執(zhí)行查詢List result = session.createQuery(queryString)
.setString("usernameString ", usernameString )
.setString("passwordString", passwordString)
.list();
使用positional parameter
usernameString//前臺(tái)輸入的用戶名passwordString//前臺(tái)輸入的密碼//hql語(yǔ)句String queryString = "from User t where t.username=? and t.password=?";//執(zhí)行查詢List result = session.createQuery(queryString)
.setString(0, usernameString )
.setString(1, passwordString)
.list();
兩者比較:positional parameter可讀性強(qiáng)不如named parameter的強(qiáng),而且可維護(hù)性差,如果我們的查詢稍微改變一點(diǎn),將第一個(gè)參數(shù)和第二個(gè)參數(shù)改變一下位置,
這樣我們的代碼中涉及到位置的地方都要修改,所以我們強(qiáng)烈建議使用named parameter方式進(jìn)行參數(shù)綁定。
最后,在named parameter中可能有一個(gè)參數(shù)出現(xiàn)多次的情況,應(yīng)該怎么處理呢?
在舉個(gè)栗子~~
我們模仿一下用戶登錄的場(chǎng)景:這次業(yè)務(wù)變換,有的網(wǎng)站,手機(jī)號(hào)可以作為用戶名來(lái)登錄,也能作為手機(jī)號(hào)本身登錄。
常見的做法是將前臺(tái)獲取到的用戶名or手機(jī)號(hào)和密碼,作為字符串動(dòng)態(tài)拼接到查詢語(yǔ)句中,然后去調(diào)用數(shù)據(jù)庫(kù)查詢~查詢的結(jié)果不為null就代表用戶存在,則登陸成功,否則登錄失敗!
正常情況下用戶輸入賬號(hào)是13812345678和密碼123
這里usernameString作為手機(jī)號(hào)又作為用戶名出現(xiàn)了兩次,怎么辦呢?
大家請(qǐng)看下面代碼:
usernameString//前臺(tái)輸入的用戶名passwordString//前臺(tái)輸入的密碼//hql語(yǔ)句String queryString = "from User t where t.username:usernameString and
t.phone:usernameString and t.password: passwordString";//執(zhí)行查詢List result = session.createQuery(queryString)
.setString("usernameString ", usernameString )
.setString("passwordString", passwordString)
.list();
在Hibernate+spring中g(shù)etHibernateTemplate()返回的對(duì)象可以調(diào)用find(String queryString, Object value...Object value)來(lái)實(shí)現(xiàn)named parameter。比如:
usernameString//前臺(tái)輸入的用戶名passwordString//前臺(tái)輸入的密碼//hql語(yǔ)句String queryString = "from User t where t.username:usernameString and t.password: passwordString";//執(zhí)行查詢r(jià)eturn getHibernateTemplate().find(queryString, usernameString, passwordString);
PS:其實(shí)說(shuō)這么多都是扯淡,因?yàn)楝F(xiàn)在真是商業(yè)項(xiàng)目中,沒有把密碼以明文的方式存入數(shù)據(jù)庫(kù)的,基本上都是經(jīng)過(guò)加密以后進(jìn)行比對(duì)。所以不管用戶輸入什么都會(huì)解密成一個(gè)字符串。所以,這種SQL注入基本上已經(jīng)不存在了~~~~
所以還是建議大家在開發(fā)中,多規(guī)范一下自己的代碼,讓代碼更加健壯!
以上就是怎樣利用Hibernate來(lái)防止SQL注入的方法的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
學(xué)習(xí)教程快速掌握從入門到精通的SQL知識(shí)。