009、PreparedStatement接口---解决SQL注入问题(输入特殊字符能登录)

该对象有Connection对象的方法prepareStatement(String sql)  返回

PreparedStatement:执行sql的对象

一、继承结构与作用

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

PreparedStatement是Statement接口的子接口,继承于父接口中所有的方法。它是一个预编译的SQL语句

作用:

1)  因为有预先编译的功能,提高SQL的执行效率。
2)  可以有效的防止SQL注入的问题,安全性更高。

二、执行原理

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 三、PreparedStatement接口中的方法

PreparedStatement方法
方法 描述
int executeUpdate() 执行DML,增删改的操作,返回影响的行数。
ResultSet executeQuery() 执行DQL,查询的操作,返回结果集

四、PreparedSatement的好处
1.prepareStatement()会先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。减少SQL编译次数,提高效率。
2.安全性更高,没有SQL注入的隐患。
3.提高了程序的可读性

五、注入问题

    1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
        (1). 输入用户随便,输入密码:a' or 'a' = 'a
        (2). sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a' 
    
    2. 解决sql注入问题:使用PreparedStatement对象来解决
    3. 预编译的SQL:参数使用?作为占位符
    4. 步骤:
        (1). 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
        (2). 注册驱动
        (3). 获取数据库连接对象 Connection
        (4). 定义sql
            * 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
        (5). 获取执行sql语句的对象 PreparedStatement  Connection.prepareStatement(String sql) 
        (6). 给?赋值:
            * 方法: setXxx(参数1,参数2)
                * 参数1:?的位置编号 从1 开始
                * 参数2:?的值
        (7). 执行sql,接受返回结果,不需要传递sql语句
        (8). 处理结果
         (9). 释放资源
    
    5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
        1. 可以防止SQL注入
        2. 效率更高

六、案例演示

注意:实现需要在mysql建立一个用户数据表,并输入一定的数据进行测试

在mySQL中输入如下命令:

create table user (
id int primary key auto_increment,
name varchar(20),
password varchar(20)
)
insert into user values (null,'jack','123'),(null,'rose','456');
-- 登录, SQL中大小写不敏感
select * from user where name='JACK' and password='123';
-- 登录失败
select * from user where name='JACK' and password='333';
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消 wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

案例一:存在注入问题的程序,(本质就是输入特殊字符,让JAVA组成特殊判断语句,判断结果一定为true)

用户通过提示信息输入用户名和密码

import com.net.lwgk.util.JDBCUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/*
    使用Statement存在注入问题
 */
public class Demo07JDBC {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String user = sc.next();
        System.out.println("请输入密码");
        String password = sc.next();
        boolean isRet = new Demo07JDBC().login(user,password);
        if(isRet){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
    }
    /**
     *
     * @param user_sc
     * @param password_sc
     */
    public boolean login(String user_sc,String password_sc){
        if (user_sc ==null || password_sc==null){
            return false;
        }
        Connection conn = null;
        Statement stmt = null;
        ResultSet resSet = null;
        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            String sql = "select * from user where user ='"+user_sc+"' and password = '"+password_sc+"' ";
            System.out.println(sql);
            resSet = stmt.executeQuery(sql);
            return resSet.next();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(resSet,stmt,conn);
        }
        return false;
    }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消 wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

测试注入问题:

请输入用户名:
sdfsdfsdf
请输入密码
a' or '1'='1
select * from user where user ='sdfsdfsdf' and password ='a' or '1'='1'
登录成功
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消 wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

问题分析:
 

select * from user where name='newboy' and password='a' or '1'='1'
name='newboy' and password='a' 为假
'1'='1' 真
相当于
select * from user where true; 查询了所有记录 
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消 wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

案例二:规避注入问题

import com.net.lwgk.util.JDBCUtils;

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

/*
    使用Statement存在注入问题
 */
public class Demo08JDBC {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String user = sc.next();
        System.out.println("请输入密码");
        String password = sc.next();
        boolean isRet = new Demo08JDBC().login(user,password);
        if(isRet){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
    }
    /**
     *
     * @param user_sc
     * @param password_sc
     */
    public boolean login(String user_sc,String password_sc){
        if (user_sc ==null || password_sc==null){
            return false;
        }
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet resSet = null;
        try {
            conn = JDBCUtils.getConnection();

            String sql = "select * from user where user=? and password = ? ";
            //获取执行sql对象
            stmt = conn.prepareStatement(sql);
            //给?赋值
            stmt.setString(1,user_sc);
            stmt.setString(2,password_sc);
            //执行SQL
            resSet = stmt.executeQuery();

            return resSet.next();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(resSet,stmt,conn);
        }
        return false;
    }
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==uploading.4e448015.gif转存失败重新上传取消 wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
发布了286 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/l0510402015/article/details/104711835
今日推荐