天天看點

JDBC中使用preparedStatement防止SQL注入

一、SQL注入

SQL注入是一種比較常見的網路攻擊方式,一些惡意人員在需要使用者輸入的地方,惡意輸入SQL語句的片段,通過SQL語句,實作無賬号登入,甚至篡改資料庫。

二、SQL注入執行個體

登入場景:

在一個登入界面,要求使用者輸入賬号和密碼。

我們的代碼中會有如下SQL語句:

情形1:(免賬号登入)

賬号:' or 1=1-- (--後面有一個空格)
密碼:
當我們輸入了這個賬号和密碼,那麼SQL語句就變成:

String sql="select * from user where account='' or 1=1 -- ' and password=''";

           
JDBC中使用preparedStatement防止SQL注入

這個查詢條件就變成account=‘’ 或者1=1,這個條件是恒成立的。

後面的-- ,就是注釋。

這樣就可以實作免賬号登入。

情形2:(删除資料庫)

賬号:';drop database test;-- (--後面有一個空格)
密碼:
當我們輸入了這個賬号和密碼,那麼SQL語句就變成:

String sql="select * from user where account='';drop database test;-- ' and password=''";
           
JDBC中使用preparedStatement防止SQL注入

這個查詢條件就變成account=‘’ 或者1=1,這個條件是恒成立的。

後面的-- ,就是注釋。

這樣就能删除資料庫。

三、防止SQL注入方法

使用PreparedStatement可以防止SQL注入。sql語句中的參數需要用?代替。PreparedStatement對sql預編譯後,然後調用setXX()方法設定sql語句中的參數。這樣再傳入特殊值,也不會出現sql注入的問題了。

四、登入項目

1、使用者表

使用者的賬号資訊:

create table user(
id int primary key auto_increment,
account varchar(20),
password varchar(20),
nickname varchar(20)
);

insert into user(account,password,nickname) values('Jack','123456','傑克');
insert into user(account,password,nickname) values('Mary','888888','瑪麗');

select*from user;
           
JDBC中使用preparedStatement防止SQL注入

2、項目結構

建立一個javaweb項目。Login類實作登入功能,用Junit進行單元測試,建立LoginTest類實作登入測試功能。

JDBC中使用preparedStatement防止SQL注入

3、登入實作

Login.java

package net.jdbc.test;

import java.math.BigDecimal;
import java.sql.*;

public class Login {
    //資料庫url、使用者名和密碼
    static final String DB_URL="jdbc:mysql://localhost:3306/test?";
    static final String USER="root";
    static final String PASS="root123";
    public static void login(String account,String password) {
        try {
            //1、注冊JDBC驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2、擷取資料庫連接配接
            Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
            //3、操作資料庫
            String sql="select * from user where account=? and password=?";

            //擷取操作資料庫的對象
            //用PreparedStatement可以預防SQL注入
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,account);//設定參數
            preparedStatement.setString(2,password);
            ResultSet resultSet = preparedStatement.executeQuery();//執行查詢sql,擷取結果集

            if (resultSet.next()){ //周遊結果集,取出資料
                String name = resultSet.getString("nickname");
                //輸出資料
                System.out.println(name+"登入成功");
            }else{
                System.out.println("使用者登入失敗......");
            }
            //4、關閉結果集、資料庫操作對象、資料庫連接配接
            resultSet.close();
            preparedStatement.close();
            connection.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch(SQLException e){
            e.printStackTrace();
        } catch(Exception e){
            e.printStackTrace();
        }
    }

}
           

4、登入測試

LoginTest.java

package net.jdbc.test;

import org.junit.Test;

import static org.junit.Assert.*;

public class LoginTest {

    @Test
    public void login() {
        Login.login("' or 1=1-- ","");//SQL注入測試
        Login.login("Jack","123");//正确賬号,錯誤密碼
        Login.login("Jack","123456");
        Login.login("Mary","888888");
    }
}

           

運作結果:

JDBC中使用preparedStatement防止SQL注入