demo

  • 没有防sql注入机制
  • 加入防sql注入机制



解决SQL注入问题?

  • 只要用户提供的信息不参与sql语句的编译过程,问题就解决了
  • 即使用户提供的信息中含有sql的关键字,但没有参与编译,不起作用
  • 要想用户信息不参与sql语句的编译,那必须使用java.sql.PreparedStatement
  • PreparedStatement接口继承了java.sql.Statement
  • PreparedStatement是属于预编译的数据库操作对象
  • PreparedStatement的原理是:预先对SQL语句的框架进行编译,然后再给sql
  • 解决sql注入的关键是什么
  • 用户提供的信息中即使含有sql语句的关键字,但这些关键字并没有参与编译,不起作用
  • 对比一下Statement和PreparedStatement?
  • -Statement存在sql注入问题,PreparedStament解决了sql注入问题
  • -PreparedStatement效率更高,statemnet 是编译一次执行一次,PrepareStatement 是编译一次执行N次
  • -PreparedStatement会在编译前做安全检查

  • 综上所诉: PreparedStatement使用较多,只有极少数的情况需要使用Statement

  • 什么时候必须要使用Statement ?
  • 业务方面必须支持sql注入的时候
  • Statement支持sql注入,凡是业务方面要求需要进行sql语句拼接的,必须使用Statement
  • 比如 排序按价格
    *综上,值传递用PreparedStatement,语句注入用Statement

没有防sql注入机制

package com.bjpowernode.jdbc;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class JDBC {
    public static void main(String[] args) {
        //初始化界面
      Map<String,String> userLoginInfo= initUI();
        //验证用户密码
        boolean loginSuccess= login(userLoginInfo);
        System.out.println(loginSuccess ?"登陆成功" :"登录失败");
    }
    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return FALSE 表示失败 ture 表示成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        //打标记
        boolean loginSuccess=false;
        //单独定义变量
        String loginName=userLoginInfo.get("loginName");
        String loginPwd=userLoginInfo.get("loginPwd");
        //JDBC 代码
        Connection conn =null;
        Statement stmt= null;
        ResultSet rs =null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","root");
            //3.获取数据库操作对象
            stmt=conn.createStatement();
            //4.执行sql
            String sql ="select * from t_user where loginName='"+ loginName+"' and loginPwd='"+loginPwd+"' ";
            //fdsa,fdsa' or 's'='s  数据库注入
            //SQL注入的原因
            //用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入
            rs=stmt.executeQuery(sql);//将拼接好的sql语句,发送给DBMS,DBMS进行编译sql编译
            //非法信息编译进去,扭曲了原来的sql语句含义
            if(rs.next()){
                //登陆成功
                loginSuccess=true;
            }
            //5.处理结果集
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6.释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }
    /*
    初始化用户界面
    return 用户输入的用户名和密码等信息
     */
    private static Map<String, String> initUI() {
        Scanner s =new Scanner(System.in);
        System.out.print("用户名: ");
        String loginName=s.nextLine();
        System.out.print("密码: ");
        String loginPwd =s.nextLine();
        Map<String,String> userLoginInfo =new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
}

加入防sql注入机制

package com.bjpowernode.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
 * 解决SQL注入问题?
 * 只要用户提供的信息不参与sql语句的编译过程,问题就解决了
 * 即使用户提供的信息中含有sql的关键字,但没有参与编译,不起作用
 * 要想用户信息不参与sql语句的编译,那必须使用java.sql.PreparedStatement
 * PreparedStatement接口继承了java.sql.Statement
 * PreparedStatement是属于预编译的数据库操作对象
 * PreparedStatement的原理是:预先对SQL语句的框架进行编译,然后再给sql
 * 解决sql注入的关键是什么
 *用户提供的信息中即使含有sql语句的关键字,但这些关键字并没有参与编译,不起作用
 */
public class JDBC2 {
    public static void main(String[] args) {
        //初始化界面
        Map<String,String> userLoginInfo= initUI();
        //验证用户密码
        boolean loginSuccess= login(userLoginInfo);
        System.out.println(loginSuccess ?"登陆成功" :"登录失败");
    }
    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return FALSE 表示失败 ture 表示成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        //打标记
        boolean loginSuccess=false;
        //单独定义变量
        String loginName=userLoginInfo.get("loginName");
        String loginPwd=userLoginInfo.get("loginPwd");
        //JDBC 代码
        Connection conn =null;
        //Statement stmt= null;//换掉
        PreparedStatement ps =null;//这里使用PreparedStatement(预编译的数据库操作对象)
        ResultSet rs =null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","root");
            //3.获取预编译的数据库操作对象
           // stmt=conn.createStatement();
            //sql语句的框子,其中 一个  ? 表示一个占位符,将来接收一个"值",?不能用''括起来,不然就没用了.
            String sql ="select * from t_user where loginName= ? and loginPwd= ? ";
            //程序执行到此处,会发送sql语句的框子给DBMS,然后DBMS进行sql语句的预先编译.
            ps=conn.prepareStatement(sql);
            //给占位符?传值(第1个问号下标是1,第二个?下标是2,JDBC中所有的下标从1开始.)
            ps.setString(1,loginName);
            ps.setString(2,loginPwd);
            //4.执行sql
            //String sql ="select * from t_user where loginName='"+ loginName+"' and loginPwd='"+loginPwd+"' ";
            //fdsa,fdsa' or 's'='s  数据库注入
            //SQL注入的原因
            //用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入
            rs=ps.executeQuery();
            //rs=stmt.executeQuery(sql);//将拼接好的sql语句,发送给DBMS,DBMS进行编译sql编译
            //非法信息编译进去,扭曲了原来的sql语句含义
            if(rs.next()){
                //登陆成功
                loginSuccess=true;
            }
            //5.处理结果集
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6.释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }
    /*
    初始化用户界面
    return 用户输入的用户名和密码等信息
     */
    private static Map<String, String> initUI() {
        Scanner s =new Scanner(System.in);
        System.out.print("用户名: ");
        String loginName=s.nextLine();
        System.out.print("密码: ");
        String loginPwd =s.nextLine();
        Map<String,String> userLoginInfo =new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
}