JDBC中Statement的Sql注入問(wèn)題詳解
Statement的Sql注入問(wèn)題
sql注入攻擊指的是通過(guò)構(gòu)建特殊的輸入作為參數(shù)傳入web應(yīng)用程序,而這些輸入大都是sql語(yǔ)法里的一些組合,通過(guò)執(zhí)行sql語(yǔ)句進(jìn)而執(zhí)行攻擊者所要做的操作,其產(chǎn)生的主要原因在于應(yīng)用程序沒(méi)有細(xì)致地過(guò)濾用戶輸入的數(shù)據(jù),致使非法數(shù)據(jù)侵入系統(tǒng)。
我們通過(guò)一個(gè)用戶登錄的小案例來(lái)大致了解sql注入的情況:(Oracle數(shù)據(jù)庫(kù)環(huán)境)
首先準(zhǔn)備一張表t_user:

create table t_user( name varchar2(10) primary key, password varchar2(10) not null )
插入一些測(cè)試數(shù)據(jù):
insert into t_user(name,password) values('tom','123');
insert into t_user(name,password) values('mary','456');
commit;
所使用的數(shù)據(jù)庫(kù)驅(qū)動(dòng):ojdbc8.jar
用JDBC連接數(shù)據(jù)庫(kù),寫(xiě)一個(gè)登錄案例:
public class TestSqlInjection {
public static void main(String[] args) {
String driverClass = "oracle.jdbc.OracleDriver";
String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
String user = "briup";
String password = "briup";
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName(driverClass);
conn = DriverManager.getConnection(url, user, password);
stmt = conn.createStatement();
System.out.println("請(qǐng)輸入用戶名:");
String uname = input.nextLine();
System.out.println("請(qǐng)輸入密碼:");
String upass = input.nextLine();
String sql = "SELECT name,password FROM t_user WHERE name='" + uname + "' AND password='" + upass + "'";
// uname xxx
// upass xxx' or '1'='1
rs = stmt.executeQuery(sql);
if (rs.next()) {
System.out.println("登錄成功");
// 這時(shí)候我們認(rèn)為用戶名和密碼都正確情況下查詢出來(lái)的用戶肯定只有一條
System.out.println("歡迎您," + uname);
} else {
System.err.println("用戶名或密碼錯(cuò)誤!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
效果:

很顯然使用Statement的確產(chǎn)生了sql注入的問(wèn)題。
但是使用PreparedStatement可以有效解決這個(gè)問(wèn)題。
public class TestSqlInjection {
public static void main(String[] args) {
String driverClass = "oracle.jdbc.OracleDriver";
String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
String user = "briup";
String password = "briup";
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
Class.forName(driverClass);
conn = DriverManager.getConnection(url, user, password);
String sql = "SELECT name,password FROM t_user WHERE name=? AND password=?";
ps = conn.prepareStatement(sql);
//uname xxx
//upass xxx' or '1'='1
System.out.println("請(qǐng)輸入用戶名:");
String uname = input.nextLine();
ps.setString(1, uname);
System.out.println("請(qǐng)輸入密碼:");
String upass = input.nextLine();
ps.setString(2, upass);
rs = ps.executeQuery();
if (rs.next()) {
System.out.println("登錄成功");
System.out.println("歡迎您," + uname);
} else {
System.err.println("用戶名或密碼錯(cuò)誤!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
PreparedStatement 除了可以防止sql注入,在執(zhí)行大量重復(fù)性插入語(yǔ)句時(shí),也會(huì)明顯提升程序運(yùn)行的性能,同時(shí)避免了繁瑣的字符串拼接操作。
對(duì)比:
Statement ,是每次執(zhí)行一個(gè)sql語(yǔ)句,就要把一個(gè)完成的sql語(yǔ)句發(fā)送給數(shù)據(jù)庫(kù)進(jìn)行執(zhí)行,然后取回返回的結(jié)果。
PreparedStatement ,可以把一個(gè)sql語(yǔ)句的結(jié)構(gòu),提前發(fā)送給數(shù)據(jù)庫(kù)進(jìn)行預(yù)處理,然后在專(zhuān)門(mén)給發(fā)送要操作的具體的值,在數(shù)據(jù)量大的時(shí)候,這種方式會(huì)大大提高執(zhí)行效率。
到此這篇關(guān)于JDBC中Statement的Sql注入問(wèn)題詳解的文章就介紹到這了,更多相關(guān)Statement的Sql注入問(wèn)題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
RabbitMQ排他性隊(duì)列Exclusive Queue詳解
這篇文章主要介紹了RabbitMQ排他性隊(duì)列Exclusive Queue詳解,如果你想創(chuàng)建一個(gè)只有自己可見(jiàn)的隊(duì)列,即不允許其它用戶訪問(wèn),RabbitMQ允許你將一個(gè)Queue聲明成為排他性的Exclusive Queue,需要的朋友可以參考下2023-08-08
Spring?Boot+Aop記錄用戶操作日志實(shí)戰(zhàn)記錄
在Spring框架中使用AOP配合自定義注解可以方便的實(shí)現(xiàn)用戶操作的監(jiān)控,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot+Aop記錄用戶操作日志實(shí)戰(zhàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04
Java BufferedReader相關(guān)源碼實(shí)例分析
這篇文章主要介紹了Java BufferedReader相關(guān)源碼實(shí)例分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
一文掌握Spring Cookie和Session 是什么及區(qū)別介紹
Cookie和Session都是用于在客戶端和服務(wù)器之間傳遞信息的技術(shù),但它們的工作方式和使用場(chǎng)景有所不同,Cookie是在客戶端保存用戶信息的一種機(jī)制,而Session是在服務(wù)器端保存用戶信息的一種機(jī)制,本文介紹Spring Cookie和Session 是什么,感興趣的朋友一起看看吧2025-01-01
Java前端Layer.open.btn驗(yàn)證無(wú)效解決方法
在本篇文章里我們給大家整理了一篇關(guān)于Java前端Layer.open.btn驗(yàn)證無(wú)效解決方法以及實(shí)例代碼,需要的朋友們可以參考學(xué)習(xí)下。2019-09-09
javafx實(shí)現(xiàn)圖片3D翻轉(zhuǎn)效果方法實(shí)例
程序?qū)崿F(xiàn)思路: 在javafx中Node對(duì)象有一個(gè)effect屬性,可以用于實(shí)現(xiàn)各種特效。PerspectiveTransform特效可以使Node對(duì)象實(shí)現(xiàn)透視變換。因此我們可以通過(guò)計(jì)算透視變換中每個(gè)點(diǎn)的位置來(lái)實(shí)現(xiàn)3D翻轉(zhuǎn)特效。2013-04-04
Spring Boot Admin Server管理客戶端過(guò)程詳解
這篇文章主要介紹了Spring Boot Admin Server管理客戶端過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03

