JDBC(二)——SQL注入及解决方案

登录案例演示

1.需求:实现输入用户名和密码后,实现跳转到主页面的功能
2.逻辑分析:

  • 客户端:接收用户名和密码,并将这些信息发送到服务端
  • 服务端:接收到客户端传过来的用户名和密码后,进行数据库校验是否存在这样的数据,如果存在,就将用户名对应的这一条记录返回,并封装成一个User对象。返回给客户端。
  • 客户端收到返回信息后,判断Account对象是否存在,如果存在,就实现跳转.....

数据准备

DROP TABLE
IF
	EXISTS bank_account;
	
	
CREATE TABLE bank_account (
	id INT PRIMARY KEY auto_increment COMMENT '主键',
	account_id VARCHAR ( 18 ) NOT NULL COMMENT '用户账号',
	account_balance DOUBLE ( 10, 2 ) COMMENT '账户余额',
	user_name VARCHAR ( 20 ) NOT NULL COMMENT '用户名称',
	user_pwd VARCHAR ( 18 ) UNIQUE COMMENT '用户密码',
	user_idcard VARCHAR ( 18 ) UNIQUE COMMENT '身份证',
	oper_time TIMESTAMP COMMENT '操作日期',
	gender enum ( 'f', 'm' ) COMMENT 'f 表示女性,m表示男性' 
);


INSERT INTO bank_account
VALUES
	( NULL, '6225113088436225', 200000, 'zhugeliang', 'zgl123456', '100000100010101000', '2019-01-01 13:10:10', 'm'); 
	
INSERT INTO bank_account
VALUES
	( NULL, '6225113088436226', 1000, 'zhouyu', 'zy123456', '100000100010101001', '2019-03-01 14:10:10', 'm' );


INSERT INTO bank_account
VALUES
	( NULL, '6225113088436227', 210000, 'caocao', 'cc123456', '100000100010101002', '2019-04-01 14:10:10', 'm' );


INSERT INTO bank_account
VALUES
	( NULL, '6225113088436228', 500, 'niumo', 'nm123456', '100000100010101003', '2019-03-01 10:10:10', 'm' );
COMMIT;



SELECT
	* 
FROM
	banK_account;

客户端

public class Client {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入账号:");
        String account_id=scanner.nextLine();
        System.out.println("请输入密码:");
        String password=scanner.nextLine();
        Server server=new Server();
        Account account = server.checkLogin(account_id, password);
        if(account==null){
            System.out.println("...密码或账号错误,请重新输入...");
        }else {
            System.out.println("...正在跳转...");
        }
    }
}

服务端

public class Server {
    public Account checkLogin(String accountId,String password){
        Connection conn=null;
        Statement stat=null;
        ResultSet res=null;
        Account account=null;
        try{
            conn=DBUtil.getConnection();
            stat=conn.createStatement();
            String sql="select id,account_id,account_balance,user_name,user_idcard,gender from bank_account where account_id='"+accountId+"' and user_pwd='"+password+"'";
            res = stat.executeQuery(sql);
            if(resultSet.next()){
                int id = resultSet.getInt("id");
                double balance = resultSet.getDouble("account_balance");
                String account_id=resultSet.getString("account_id");
                String realName = resultSet.getString("user_name");
                String idcard = resultSet.getString("user_idcard");
                String gender = resultSet.getString("gender");
                account=new Account(id,account_id,balance,realName,password,idcard,null,gender);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,stat,res);
        }
        return account;
    }
}

用户

public class Account {
    //提供属性
    private int id;
    private String account_id;
    private double balance;
    private String realName;
    private String password;
    private String idcard;
    private Timestamp timestamp;
    private String gender;
    //提供无惨构造器
    public Account(){}
    //提供全参构造器

    public Account(int id, String account_id, double balance, String realName, String password, String idcard, Timestamp timestamp, String gender) {
        this.id = id;
        this.account_id = account_id;
        this.balance = balance;
        this.realName = realName;
        this.password = password;
        this.idcard = idcard;
        this.timestamp = timestamp;
        this.gender = gender;
    }
    //为属性提供get/set方法

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAccount_id() {
        return account_id;
    }

    public void setAccount_id(String account_id) {
        this.account_id = account_id;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getIdcard() {
        return idcard;
    }

    public void setIdcard(String idcard) {
        this.idcard = idcard;
    }

    public Timestamp getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Timestamp timestamp) {
        this.timestamp = timestamp;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    //提供equal方法和hashCode方法

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Account account = (Account) o;
        return id == account.id &&
                Double.compare(account.balance, balance) == 0 &&
                Objects.equals(account_id, account.account_id) &&
                Objects.equals(realName, account.realName) &&
                Objects.equals(password, account.password) &&
                Objects.equals(idcard, account.idcard) &&
                Objects.equals(timestamp, account.timestamp) &&
                Objects.equals(gender, account.gender);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, account_id, balance, realName, password, idcard, timestamp, gender);
    }
    public String toString(){
        return account_id+"\t"+balance+"\t"+realName;
    }
}

DBUtil

public class DBUtil{
    //添加静态属性
    private static String driverclass;
    private static String url;
    private static String user;
    private static String password;
    static {
        try{
            //获取流
            InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
            //获取Properties对象
            Properties properties=new Properties();
            //加载properties文件到内存
            //properties文件内容参考入门篇
            properties.load(in);
            //对静态属性赋值
            driverclass=properties.getProperty("driverclass");
            url=properties.getProperty("url");
            user=properties.getProperty("user");
            password=properties.getProperty("password");
            //加载驱动到内存
            Class.forName(driverclass);
            //关闭流
            in.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //获取Connection对象
    public static Connection getConnection(){
        try{
            Connection connection = DriverManager.getConnection(url, user, password);
            return  connection;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //关闭连接
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        try{
            if(resultSet!=null){
                resultSet.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


原因分析


String sql = "select id,account_id,account_balance,user_name,user_idcard,gender from bank_account where account_id='" + accountId + "' and user_pwd='" + password + "'";

# 实际sql 
SELECT
	id,
	account_id,
	account_balance,
	user_name,
	user_idcard,
	gender 
FROM
	bank_account 
WHERE
	account_id = '6225113088436225' 
	AND user_pwd = 'hhhhhqaedggevfsdhhhhhh' 
	OR '1' = '1'
# 这里的条件恒为真

PreparedStatement类

  • PreparedStatement是Statement的子类型

  • 此类型可以确定SQL语句的结构,无法通过其它方式来增减条件。

  • 此类型还通过占位符 "?"来提前占位,并确定语句的结构。

  • 提供了相应的赋值方式:

    • setInt(int index,int value)
    • setString(int index,String value)
    • setDouble(int index,double value)
    • setDate(int index,Date value) index:表示sql语句中占位符?的索引。从1开始 value:占位符所对应的要赋予的值
  • 执行方法:

    • execute() ;------用于DDL和DML
    • executeUpdate();-----用于DML
    • executeQuery();-----用于DQL

修改Server里的代码

public class Server1 {
    public Account checkLogin(String accountId,String password) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;
        Account account = null;
        try {
            conn = DBUtil.getConnection();
            String sql = "select id,account_id,account_balance,user_name,user_idcard,gender from bank_account where account_id=? and ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,accountId);
            ps.setString(2,password);
            resultSet= ps.executeQuery();
            if(resultSet.next()){
                int id = resultSet.getInt("id");
                double balance = resultSet.getDouble("account_balance");
                String realName = resultSet.getString("user_name");
                String idcard = resultSet.getString("user_idcard");
                String gender = resultSet.getString("gender");
                account = new Account(id,accountId,balance,realName,password,idcard,null,gender);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, resultSet);
        }
        return account;
    }
}

修改Client代码

public class Client {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入账号:");
        String account_id=scanner.nextLine();
        System.out.println("请输入密码:");
        String password=scanner.nextLine();
        //Server server=new Server();
        //Account account = server.checkLogin(account_id, password);
        Server1 server1=new Server1();
        Account account = server1.checkLogin(account_id, password);
        if(account==null){
            System.out.println("...密码或账号错误,请重新输入...");
        }else {
            System.out.println("...正在跳转...");
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/dch-21/p/12920178.html