一、什么是SQL注入
SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。
二、模擬SQL注入
我們先創建一個簡單的數據庫和一個user表:
create database test;
use database test;
create table user(username varchar(20), password(20));
我們在表中插入兩個數據:
insert into user values('zack', '123456');
insert into user values('rudy', '123456');
我們再看一個簡單的Java程序:
package com.zack.sql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Sql {
//鏈接的url
private static String url = "jdbc:mysql:///all_test?serverTimezone=GMT";
//用戶名
private static String user = "root";
//密碼
private static String password = "123456";
//用于輸入
Scanner sc = new Scanner(System.in);
public static void main(String[] args) throws Exception {
//加載驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取連接
Connection conn = DriverManager.getConnection(url, user, password);
//獲取statment對象
Statement stat = conn.createStatement();
//要求用戶輸入用戶名和密碼
System.out.println("請輸入你的用戶名:");
String name = sc.next();
System.out.println("請輸入密碼:");
String pwd = sc.next();
//code1、通過用戶輸入的用戶名和密碼來查詢數據庫中是否存在該用戶
ResultSet set = stat.executeQuery("select * from user where username = '" + name + "' and password = '" + pwd + "'");
//將匹配到的數據打印出來
while(set.next()) {
String username = set.getString("username");
String password = set.getString("password");
System.out.println("name:" + username + ", pwd:" + password);
}
}
}
我們看到code1,假設我們輸入的如下:
zack
123456
這個正好是與我們數據庫中匹配的,那么code1中執行的sql語句如下:
select * from user where username = 'zack' and password = '123456';
我們原本設想的是,如果輸入不匹配的數據,將無法在數據庫中查找到相應的東西,但是我們進行如喜愛輸入:
zack' or '1' = '1
111
這個時候,code1中執行的語句如下:
select * from user where username = 'zack' or '1'='1' and password = '123456';
其中’1’ = '1’是恒為真的,所以這個sql語句不會再去判斷密碼是否正確,這樣就完成了SQL注入攻擊的效果。
三、如何防止SQL注入
防止sql注入的方法也非常簡單,在jdbc中有一個sql語句預編譯的對象,我們可以通過PrepareStatement類來實現。假設我們還是要執行查詢操作,執行語句如下:
String sql = "select * from user where username = ? and password = ?";
這里我們使用“?”來表示字段的值。然后我們來創建一個PrepareStatement對象,這里和Statement有些不一樣:
//在創建PrepareStatement對象時,就傳入了sql語句
PrepareStatement preStat = conn.prepareStatement(sql);
這里是在創建PrepareStatement對象時就傳入了sql語句,而Statement是在執行查詢操作時才傳入sql語句。
因為我們已經傳入了sql語句,所以在執行查詢時不需要傳入sql語句,但是要多一步匹配參數的操作:
//將name的值替換到sql語句中第一個?
preStet.setString(1, name);
//將name的值替換到sql語句中第二個?
preStat.setString(2, pwd);
其中name和pwd是我們輸入的字符串變量。接下來我們就可以進行查詢操作了:
ResultSet set = preStat.executeQuery();
while(set.next()) {
String username = set.getString("username");
String password = set.getString("password");
System.out.println("name:" + username + ", pwd:" + password);
}
這里操作和之前類似,只是不需要傳入sql語句。完整代碼如下:
package com.zack.sql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Sql {
private static String url = "jdbc:mysql:///all_test?serverTimezone=GMT";
private static String user = "root";
private static String password = "123456";
private static Scanner sc = new Scanner(System.in);
private static String sql = "select * from user where username = ? and password = ?";
public static void main(String[] args) throws Exception {
//數據庫操作
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement stat = conn.prepareStatement(sql);
//要求用戶輸入用戶名和密碼
System.out.println("請輸入你的用戶名:");
String name = sc.next();
System.out.println("請輸入密碼:");
String pwd = sc.next();
//通過用戶輸入的用戶名和密碼來查詢數據庫中是否存在改用戶
stat.setString(1, name);
stat.setString(2, pwd);
ResultSet set = stat.executeQuery();
while(set.next()) {
String username = set.getString("username");
String password = set.getString("password");
System.out.println("name:" + username + ", pwd:" + password);
}
}
}
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。