SQL注入问题

SQL注入问题:

实现功能:

1、需求:
        模拟用户登录功能的实现。
2、业务描述:
    程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
    用户输入用户名和密码之后,提交信息,java程序收集到用户信息
    Java程字连接数据库验证用户名和密码是否合法
    合法:显示登录成功
    不合法:显示登录失败
3、数据的准备:
    在实际开发中,表的设计会使用专业的建模工具,我们这里安装一一个建模工具: PowerDesigner
    使用pD工具来进行数据库表的设计。(为了方便我已经把建表代码放在下面)

SQL表:user_login.sql:

drop table if exists t_user;

/*==============================================================*/
/* Table: t_user                                                */
/*==============================================================*/
create table t_user
(
   id                   bigint auto_increment,
   userName             varchar(255),
   userPwd              varchar(255),
   name                 varchar(255),
   primary key (id)
);
insert  into t_user(userName,userPwd,name) values('zhangsan','123','张三');
insert  into t_user(userName,userPwd,name) values('llisi','123','李四');
commit;
select * from t_user;

连接数据库测试代码:

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Test07_模拟用户登良功能的实现 {
    public static void main(String[] args) {
        //初始化一个界面的方法
        Map<String,String> userLogin = chuShiHuaUi();
        //验证用户名和密码
        Boolean dengLu = login(userLogin);
        //最后输出结果
        System.out.println(dengLu ? "登录成功!" : "登录失败!");
    }

    private static Boolean login(Map<String, String> userLogin) {
        //打标记
        Boolean b = false;

        Connection conn = null;
        Statement s = null;
        ResultSet rs = null;
        try{
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/donglijiedian","root","zhixi158");
            //3、获取数据库操作对象
            s = conn.createStatement();
            //4、操作MySQL //SQL语句中字符串是'',要想获取数据要加双引号,中间加上数据

            String sql = "select * from t_user where userName = '"+userLogin.get("userName")+"' and userPwd = '"+userLogin.get("userPwd")+"'";
            rs = s.executeQuery(sql);
            //5、处理查询结果集
            //用户名错的情况下查不到记录,用户名正确情况下也最多查出一条记录,所以用if就够了
            if(rs.next()){
                return true;//如果存在这条记录就返回
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            //6、释放资源,由内到外
            try{
                if(rs != null)
                    rs.close();
            }catch(Exception e){
                e.printStackTrace();
            }
            
            try{
                if(s != null)
                    s.close();
            }catch(Exception e){
                e.printStackTrace();
            }

            try{
                if(conn != null)
                    conn.close();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        return b;
    }

    private static Map<String, String> chuShiHuaUi() {
        Scanner s = new Scanner(System.in);
        //获取用户名
        System.out.println("用户名:");
        String userName  = s.nextLine();//nextLine返回一行数据

        //获取密码
        System.out.println("密码:");
        String userPwd = s.nextLine();

        //组装Map集合
        Map<String,String> userLogin  = new HashMap<>();
        userLogin.put("userName",userName);//添加用户名
        userLogin.put("userPwd",userPwd);//添加密码
        return userLogin;//返回集合数据
    }
}

SQL注入问题:

在我们测试的时候,验证用户名和密码发现是没有问题的。

 但是我们输入一些特定的字符,就发现了问题:

 

 发现输入一些执行的字符会出现登录成功,这显然是不符合我们的需求的。

如何解决/避免SQL注入问题

PreparedStatement和Statement的区别:

/**
 * 1、对比一下Statement和PreparedStatement?
     * statement存在sq1注入问题,PreparedStatement解诀了sql注入问题。
     * Statement是编译一次执行一 次。PreparedStatement是编译一次, 可执行N次。                    
     * PreparedStatement会在编译阶段做类型的安全检查。
 * 综上所述: PreparedStatement使用较多。只有极少数的情况下需要使用Statement
 * 2、什么情况下必须使用Statement呢?
     * 业务方面要求必须支持sQL注入的时候。
     * Statement支持sQL注入,凡是业务方面要求是需要进行sq1语句拼接的,必须使用Statement 
 */

实现代码:

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Test08_解决SQL注入问题 {
    public static void main(String[] args) {
        //初始化一个界面的方法
        Map<String,String> userLogin = chuShiHuaUi();
        //验证用户名和密码
        Boolean dengLu = login(userLogin);
        //最后输出结果
        System.out.println(dengLu ? "登录成功!" : "登录失败!");
    }

    private static Boolean login(Map<String, String> userLogin) {
        //打标记
        Boolean b = false;

        Connection conn = null;
        //PreparedStatement 是Statement的一个接口
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/donglijiedian","root","zhixi158");
            //3、获取 预编译 的数据库操作对象
            // sQL语句的框子。其中一个?,表示一个占位符,一个?将来接收一个“值”, 注意:占位符不能使用单引号括起来。
            String sql = "select * from t_user where userName = ? and userPwd = ?";
            //程序执行到此处,会发送sq1语句框子给DBMS,然后DBMS进行sql语句的预先编译。
            ps = conn.prepareStatement(sql);
            //给占位符?传值(第1个问号下标是1,第2个问号下标是2,JDBC中 所有下标从1开始。)
            ps.setString(1,userLogin.get("userName"));
            ps.setString(2,userLogin.get("userPwd"));

            //4、执行SQL
            rs = ps.executeQuery();

            //5、处理查询结果集
            //用户名错的情况下查不到记录,用户名正确情况下也最多查出一条记录,所以用if就够了
            if(rs.next()){
                return true;//如果存在这条记录就返回
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            //6、释放资源,由内到外
            try{
                if(rs != null)
                    rs.close();
            }catch(Exception e){
                e.printStackTrace();
            }

            try{
                if(ps != null)
                    ps.close();
            }catch(Exception e){
                e.printStackTrace();
            }

            try{
                if(conn != null)
                    conn.close();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        return b;
    }


    private static Map<String, String> chuShiHuaUi() {
        Scanner s = new Scanner(System.in);
        //获取用户名
        System.out.println("用户名:");
        String userName  = s.nextLine();//nextLine返回一行数据

        //获取密码
        System.out.println("密码:");
        String userPwd = s.nextLine();

        //组装Map集合
        Map<String,String> userLogin  = new HashMap<>();
        userLogin.put("userName",userName);//获取用户名
        userLogin.put("userPwd",userPwd);//获取密码
        return userLogin;//返回集合数据
    }
}

 

posted @ 2020-12-09 17:04  Java小白的搬砖路  阅读(155)  评论(0编辑  收藏  举报