前言
sql注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的sql語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。
1、sql注入案例
模擬一個用戶登錄的sql注入案例,用戶在控制臺上輸入用戶名和密碼, 然后使用 statement 字符串拼接的方式實現用戶的登錄。
1.1 數據庫中先創建用戶表及數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
-- 創建一張用戶表 create table `users` ( `id` int (11) not null auto_increment, `username` varchar (20), ` password ` varchar (50), primary key (`id`) ) engine=innodb default charset=utf8; -- 插入數據 insert into users(username,` password `) values ( '張飛' , '123321' ),( '趙云' , 'qazxsw' ),( '諸葛亮' , '123qwe' ); insert into users(username,` password `) values ( '曹操' , '741258' ),( '劉備' , 'plmokn' ),( '孫權' , '!@#$%^' ); -- 查看數據 select * from users; |
1.2 編寫一個登錄程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
package com.study.task0201; import java.sql.*; import java.util.scanner; public class testsqlin { public static void main(string[] args) throws classnotfoundexception, sqlexception { class.forname( "com.mysql.jdbc.driver" ); string url = "jdbc:mysql://127.0.0.1:3306/testdb?characterencoding=utf-8" ; connection conn = drivermanager.getconnection(url, "root" , "123456" ); //system. out .println(conn); // 獲取語句執行平臺對象 statement statement smt = conn.createstatement(); scanner sc = new scanner(system. in ); system. out .println( "請輸入用戶名:" ); string username = sc.nextline(); system. out .println( "請輸入密碼:" ); string password = sc.nextline(); string sql = "select * from users where username = '" + username + "' and password = '" + password + "'" ; //打印出sql system. out .println(sql); resultset resultset = smt.executequery(sql); if(resultset. next ()){ system. out .println( "登錄成功!!!" ); } else { system. out .println( "用戶名或密碼錯誤,請重新輸入!!!" ); } resultset. close (); smt. close (); conn. close (); } } |
1.3 正常登錄
輸入正確的用戶名及密碼后提示"登錄成功"
1.4 登錄失敗
輸入用戶名或密碼錯誤時,提示“用戶名或密碼錯誤,請重新輸入”
1.5 模擬sql注入
拼接的字符串中有or '1'='1' 為恒成立條件,因此 及時前面的用戶及密碼不存在也會取出所有記錄,因此提示"登錄成功"
1.6 sql語法報錯
使用拼接的方式,還會出現sql語法錯誤等報錯,例如
2. 解決方案
使用statement方式,用戶可以通過字符串拼接,改變原本sql真正的含義,導致存在sql注入的風險。解決sql注入,可以通過預處理對象preparedstatement來代替statement進行處理。
2.1 程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import java.sql.*; import java.util.scanner; public class testsqlin { public static void main(string[] args) throws classnotfoundexception, sqlexception { class.forname( "com.mysql.jdbc.driver" ); string url = "jdbc:mysql://127.0.0.1:3306/testdb?characterencoding=utf-8" ; connection conn = drivermanager.getconnection(url, "root" , "123456" ); //system. out .println(conn); // 獲取語句執行平臺對象 statement // statement smt = conn.createstatement(); scanner sc = new scanner(system. in ); system. out .println( "請輸入用戶名:" ); string username = sc.nextline(); system. out .println( "請輸入密碼:" ); string password = sc.nextline(); string sql = "select * from users where username = ? and password = ? " ; // system. out .println(sql); // resultset resultset = smt.executequery(sql); preparedstatement preparedstatement = conn.preparestatement(sql); preparedstatement.setstring(1,username); preparedstatement.setstring(2, password ); resultset resultset = preparedstatement.executequery(); if(resultset. next ()){ system. out .println( "登錄成功!!!" ); } else { system. out .println( "用戶名或密碼錯誤,請重新輸入!!!" ); } preparedstatement. close (); resultset. close (); // smt. close (); conn. close (); } } |
2.2 正常登錄
2.3 用戶名密碼錯誤
當用戶名或密碼輸入錯誤時,會提示“用戶名或密碼錯誤,請重新輸入”
2.4 模擬sql注入
按照之前的情況,進行sql注入的寫法,測試后不再出現sql注入情況。
2.5 模擬sql語法錯誤
使用預處理類后,輸入帶有單引號或雙引號的內容也不會再出現sql語法錯誤的報錯
3. 小結
statement 與 preparedstatement的主要區別如下:
- statement用于執行靜態sql語句,在執行時,必須指定一個事先準備好的sql語句
- preparestatement是預編譯的sql語句對象,語句中可以包含動態參數“?”,在執行時可以為“?”動態設置參數值
- preparestatement可以減少編譯次數提高數據庫性能
總結
到此這篇關于sql注入以及如何解決的文章就介紹到這了,更多相關sql注入及解決內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/gjc592/p/14167666.html