1.關(guān)于SQL注入
什么是SQL注入:
由于jdbc程序在執(zhí)行的過程中sql語句在拼裝時使用了由頁面?zhèn)魅雲(yún)?shù),,如果用戶惡意傳入一些sql中的特殊關(guān)鍵字,會導(dǎo)致sql語句意義發(fā)生變化,這種攻擊方式就叫做sql注入,,參考用戶注冊登錄案例,。
首先看一下以下代碼:
- String sql = "select* from users where username='" + userName
- + "' and password='" + passWord+"'";
- Connection conn = null;
- Statement state = null;
- ResultSet result;
- conn = JdbcUtil.getConnection();
- System.out.println(sql);
- try {
- state = conn.createStatement();
- result = state.executeQuery(sql);
這是一段根據(jù)傳入用戶名,密碼查找用戶表的代碼,。
在做用戶登錄的驗證的時候,我們可能會根據(jù)用戶所填寫的用戶名和密碼在后臺拼成一條SQL語句執(zhí)行,,去查用戶表:
select* from users where username='張三' and password='小張',,如果能查出結(jié)果則表示驗證成功,允許登錄,,否則賬號或密碼錯誤不允許登錄,。那么在組成這條語句的過程中會存在一個叫做SQL注入的問題,就是用戶在輸入用戶名或密碼的時候填寫某些內(nèi)容使得后臺所拼成的SQL語句語義有所變化,。
舉個例子,,在沒有防止SQL的情況下:假如我們知道一個用戶叫做張三,但是不知道這個用戶的密碼是什么,,我們依然可以在登錄的時候在用戶輸入框?qū)懮希簭埲?# 然后密碼框任意填:njksad,。一點擊登錄,會發(fā)現(xiàn)居然能夠登錄上去,。那是為什么呢,?
這是因為#在SQL中的意思是注釋,那么我們根據(jù)上面的情況來分析一下最終所拼成的SQL語句是怎樣的,,
select* from users where username='張三'#' and password='njksad'
為了讓大家能夠看清楚上面那條SQL語句,,筆者特地加大顯示,可以看到 username='張三'
之后是一個#
那就意味著之后的內(nèi)容都是注釋,,也就是可以忽略掉那么這條語句真正發(fā)揮作用的部分就是:select* from users where username='張三'
直接變成了一條查找張三 的語句,完全不用經(jīng)過密碼驗證,。
2.防止SQL注入攻擊
那么怎么才能做到防止SQL注入攻擊呢?
在上面那段代碼中,,Statement的對象是用來執(zhí)行SQL語句的,Statement有一個子類叫做PreparedStatement,,可以做到防止SQL注入攻擊,,接下來我們來看看PreparedStatement有什么特點以及怎么使用:
PreparedStatement是Statement的孩子,不同的是,,PreparedStatement使用預(yù)編譯機制,,在創(chuàng)建PreparedStatement對象時就需要將sql語句傳入,傳入的過程中參數(shù)要用?替代,,這個過程回導(dǎo)致傳入的sql被進(jìn)行預(yù)編譯,,然后再調(diào)用PreparedStatement的setXXX將參數(shù)設(shè)置上去,由于sql語句已經(jīng)經(jīng)過了預(yù)編譯,再傳入特殊值也不會起作用了,。
而且PreparedStatement使用了預(yù)編譯機制,,sql語句在執(zhí)行的過程中效率比Statement要高。
- String sql = "select* from users where username=? and password=?";
- Connection conn = null;
- PreparedStatement state = null;
- ResultSet result;
- conn = JdbcUtil.getConnection();
- System.out.println(sql);
- try {
- state = conn.prepareStatement(sql);
- state.setString(1, userName);
- state.setString(2, passWord);
- result = state.executeQuery();
|