SQL注入詳解以及案例與防護
SQL注入是每個基於資料庫開發的研發人員,都必須要注意到的問題。
1.SQL注入的根本原因,
是攻擊者可以通過傳入系統的引數來篡改SQL語句造成。
其後果不外乎:
1) 檢視系統表結構資訊
2) 更改系統表結構資訊
3) 檢視/更改到該使用者不被允許訪問的資料表, 或表中的某些敏感資料。
2.SQL注入原理
想要防範SQL Injection, 先看看SQL是怎麼被注入的。
How SQL Injected:
最典型的是這種情形: 程式中根據使用者輸入的資料來動態構建SQL的Where條件。拿使用者登入校驗舉例:
如果根據使用者輸入的userName, password,程式中這樣構建SQL:
1 |
Stringsql= "select*fromuserswhereuser_name='" +userName+ "'andpassword='" + password + "'" ;
|
如果使用者故意輸入這樣的引數(無論引數來源方式是HTTP GET or HPPT Post, Ajax請求也是HPPT GET或POST之一):
userName="admin"
password="xxx' OR 1=1"
最終程式構造出來的SQL語句是:
1 |
"select*fromuserswhereuser_name='admin'andpassword='xxx'or1=1" ;
|
這顯然輕鬆突破了程式假定的SQL邏輯(Where 條件總是true,變得毫無用處)。
通過這種方式可以肆意更改SQL語句,比如
1 2 |
"select*fromuserswhereuser_name='admin'andpassword='xxx'or1=1unionselect*fromusers" ;
"select*fromuserswhereuser_name='admin'andpassword='xxx';deletefromusers" ;
|
等等。
其次,結合應用系統對錯誤資訊的不當處理,甚至可以窺測系統的表結構資訊:
1 |
"select*fromuserswhereuser_name='admin'andpassword='xxx'abcdef" ;
|
顯然篡改後的SQL執行肯定會報系統錯誤, 類似於:
1 |
[jdbc]SQLerrorcode=XXXX,SQL:select*fromuserswhereuser_name='admin'andpassword='xxx'abcdef,;
|
如果這個錯誤資訊直接拋到頁面上,那麼使用者立即就知道tableName=users, fieldName: user_name, password.
使用者通過SQL injection再構造這樣的SQL:
1 |
"select*fromuserswhereuser_name='admin'andpassword='xxx'unionselectuser_name,password/2fromuserwhereuser_name='admin'" ;
|
假定admin使用者的密碼是aaa111@@@, 那麼系統在執行password/2時,嘗試將aaa111@@@轉換為數值再除以2時,會發生型別轉換錯誤,類似於:
1 |
[jdbc]SQLerrorcode=XXXX,'aaa111@@@'isnotanumber.
|
如果這個錯誤資訊直接拋到頁面上,那麼使用者立即就知道admin的密碼是aaa111@@@
再次,如果應用連線到資料庫的帳號還有DDL語句的執行許可權,那就更危險了:
通過SQL Injection可以構建如下的SQL:
1 |
"select*fromuserswhereuser_name='admin'andpassword='xxx'or1=1;selecttable_namefromall_tables" ;
|
查詢系統所有的表的名稱,以及還可以破壞資料:
1 2 |
"select*fromuserswhereuser_name='admin'andpassword='xxx'or1=1;truncatetableusers" ;
"select*fromuserswhereuser_name='admin'andpassword='xxx'or1=1;droptableusers" ;
|
3.SQL注入防範
瞭解了SQL Injection的原理,防範SQL Injection就容易了:
其實防止使用者窺視系統表結構甚至執行DDL語句來破壞表結構或資料很容易:
在DB層通過限制應用程式連線到資料庫的使用者許可權即可避免系統表被使用者檢視或更改。
比如:只應該授權其必要的schema和資料庫物件的DML執行許可權即可。
絕對不應該給其執行DDL語句(Create/Drop table, Truncate Table, etc.)的許可權。
此時,就是使用者篡改了SQL, 也不能成功執行DDL語句: 系統會報無權執行此SQL!
所以程式中主要是防範黑客檢視/更改不被允許訪問的資料表, 或表中的某些敏感資料。
其實只要你堵住使用者隨意更改SQL條件的漏洞,就可以防範上述的所有SQL Injection.
再進一步,只要你使用bind variables/引數繫結即可:
1 2 3 4 5 |
StringstrSQL=SELECT*FROMuserswhereusername=?ANDpassword=?);
PreparedStatementpstmt=myConnection.prepareStatement(strSQL);
pstmt.setString( 1 ,”guest”);
pstmt.setString( 2 ,“xyzabc”);
pstmt.execute();
|
如果你使用Hibernate這樣的OR mapping 工具的話,一樣很方便地使用bind variables/引數繫結的方式來避免SQL Injection.
1 2 3 4 |
Queryq=sess.createQuery( "fromUsersuwhereu.userName=:userNameandu.password=:password" );
q.setString( "userName" , "guest" );
q.setString( "password" , "password" );
ListuserList=q.list();
|
最後,對於應用系統錯誤,你應該通過try catch住,做特定的處理,而不是隨意拋棄到頁面上,以防程式邏輯或敏感資訊洩漏
轉自 爛程式碼
https://www.trashcode.cn/post/d/e30a5883-ce4d-43f8-91a7-d66ee907237a