jdbc中Statement接口的sql注入

jdbc中Statement接口的sql注入及解决措施

代码实践
下面用最原始的jdbc连接代码演示一下

-- 环境
-- musql 8.0.12
-- jdbc jar包 mysql-connector-java-8.0.19.jar
--第一步   使用navicate创建数据库和表
-- 创建数据库
create database my_first;
-- 创建表
create table temp_user(
	u_id int primary key auto_increment,
	u_name varchar(255),
	u_password varchar(255)
)
-- 添加数据
insert into temp_user (u_name,u_password) values
('zhugeliang','zgl456'),
('zhouyu','zy326');

设计表对应的java类

import java.util.Objects;

/**
 * @author programmer trip
 * 根据表中的字段设计该类
 */
public class User {
    private int id;
    private String uName;
    private String uPassword;

    public User(){}

    public User(int id, String uName, String uPassword) {
        this.id = id;
        this.uName = uName;
        this.uPassword = uPassword;
    }

    public int getId() {
        return id;
    }

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

    public String getuName() {
        return uName;
    }

    public void setuName(String uName) {
        this.uName = uName;
    }

    public String getuPassword() {
        return uPassword;
    }

    public void setuPassword(String uPassword) {
        this.uPassword = uPassword;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        User user = (User) o;
        return id == user.id &&
                Objects.equals(uName, user.uName) &&
                Objects.equals(uPassword, user.uPassword);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, uName, uPassword);
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", uName='" + uName + '\'' +
                ", uPassword='" + uPassword + '\'' +
                '}';
    }
}

设计服务端类

import java.sql.*;

/**
 * @author programmer-trip
 *
 */
public class AppServer {

    /**
     * 用户名和密码的登录验证
     * @param userName 用户名
     * @param password 密码
     */
    public  User checkLogin(String userName,String password){
        Connection conn = null;
        Statement stat = null;
        ResultSet res = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_first?serverTimezone=UTC","root","123456");
            stat = conn.createStatement();
            String sql = "select * from temp_user where u_name = '" + userName + "' and u_password = '" + password + "'";
            res = stat.executeQuery(sql);
            while(res.next()){
                int id = res.getInt("u_id");
                String uName = res.getString("u_name");
                String uPassword = res.getString("u_password");
                return new User(id,uName,uPassword);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            try {
                if(res != null){
                    res.close();
                }
                if(stat != null){
                    stat.close();
                }
                if(conn != null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;

    }
}

设计客户端

/**
 * @author programmer_trip
 */
public class AppClient {
    public static void main(String[] args) {
    	//写法一,该写法使得sql语句中的密码验证部分变成了注释,只要用户名存在就可以直接登录
    	//String uName = "zhugeliang'#"
    	//写法二
        String uName = "zhugeliang";
        String uPassword = "11111 ' or '1' = '1";
        
        AppServer appServer = new AppServer();
        User user = appServer.checkLogin(uName,uPassword);
        if(user != null){
            System.out.println("---------------验证成功,正在跳转--------------------");
        }else {
            System.out.println("---------------密码错误,请重新输入------------------");
        }
    }
}

//运行结果
---------------验证成功,正在跳转--------------------

在temp_user表中"zhugeliang"用户的密码是"zgl456" ,但是输入实参"11111 ’ or ‘1’ = '1"却能登录成功,容易造成数据安全隐患问题.
==> 用户可以通过参数改变sql语句的条件的个数,对于以上的案例相当于如下语句

"select * from temp_user where u_name = 'zhugeliang' and u_password = '11111' or '1' = '1'"

为了解决Statement接口的sql注入问题,可以使用PreparedStatement接口代替Statement接口进行预编译sql处理.

  • PreparedStatement是Statement的子接口
  • 可以确定sql语句的结构,无法通过其他条件进行增减sql语句的条件
  • 通过 ? 提前占位,并确定语句的结构
  • 可以防止sql攻击, 提高代码可读性,提高效率(采用预编译机制,编译一次,可重复执行多次该sql语句,不需再重新编译)

现在采用PreparedStatement代替Statement之后,再来看sql注入是否成功

import java.sql.*;

/**
 * @author programmer-trip
 *
 */
public class AppServer {

    /**
     * 用户名和密码的登录验证
     * @param userName 用户名
     * @param password 密码
     */
    public  User checkLogin(String userName,String password){
        Connection conn = null;
        //更改Statement为PreparedStatement
        PreparedStatement stat = null;
        ResultSet res = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_first?serverTimezone=UTC","root","123456");
            //更改sql语句并使用 ?  进行占位
            String sql = "select * from temp_user where u_name = ?  and u_password = ?";
            stat = conn.prepareStatement(sql);
            //使用相应的setXXX方法为sql模板中的占位符赋值
            stat.setString(1,userName);
            stat.setString(2,password);
            res = stat.executeQuery();
            while(res.next()){
                int id = res.getInt("u_id");
                String uName = res.getString("u_name");
                String uPassword = res.getString("u_password");
                return new User(id,uName,uPassword);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            try {
                if(res != null){
                    res.close();
                }
                if(stat != null){
                    stat.close();
                }
                if(conn != null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;

    }
}

再次执行客户端的main方法,出现如下结果(sql注入失败)

---------------密码错误,请重新输入------------------
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值