CGB2111开班第二十四天

CGB2111开班第二十四天,第1张

CGB2111开班第二十四天 SQL注入攻击

就是利用Statement类不能对数据库的特殊符号做解释而被一些别有用心之人攻击。

SQL注入攻击会使得我们数据库的信息极为不安全。

案例:SQL注入攻击的代码案例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

public class Test {

    public static void main(String[] args) {

        dataInfo();
    }

    public static void dataInfo() {

        Scanner sc = new Scanner(System.in);

        System.out.print("请输入用户名:");

        String user_Name = sc.nextLine();

        System.out.print("请输入密码:");

        String user_password = sc.nextLine();

        Connection conn = null;

        Statement stat = null;

        ResultSet rs = null;

        String url = "jdbc:mysql://127.0.0.1:3306/cgb2111?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";

        String userName = "账号";

        String password = "密码";

        try {

            Class.forName("com.mysql.cj.jdbc.Driver");

            conn = DriverManager.getConnection(url, userName, password);

            stat = conn.createStatement();

            String sql = "select `id`, `name`, `pwd` from `user` where `name` = '" + user_Name + "' and `pwd` = '" + user_password + "'";

            rs = stat.executeQuery(sql);

            if (rs.next()) {

                System.out.println("恭喜您,登录成功");

            } else {

                System.out.println("用户名或者密码错误");
            }

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (SQLException throwables) {

            throwables.printStackTrace();

        } finally {

            try {
                if (rs != null && rs.isClosed() == false){
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {

                if (stat != null && rs.isClosed() == false){

                    stat.close();
                }
            } catch (SQLException e) {

                e.printStackTrace();
            }

            try {

                if (conn != null && conn.isClosed() == false){

                    conn.close();
                }

            } catch (SQLException e) {

                e.printStackTrace();
            }
        }
    }
}


【运行结果】
请输入用户名:赵敏' #
请输入密码:
恭喜您,登录成功

问题:当用户输入特殊值:jack' #时,甚至不需要密码也能登录

原因:# 在SQL中表示注释的意思,相当于后面的条件被注释掉了...

select `id`,`name`, `pwd` from user where name = '赵敏' #' pwd = '';

现象叫SQL注入/SQL攻击,本质上就是因为SQL语句中出现了特殊的符号。

导致了SQL语义发生了改变。

Statement低效、不安全。

解决方案:放弃Statement的使用,改用PreparedStatement。

解决SQL注入攻击的,改造后的代码

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.util.Scanner;

public class Test {

    public static void main(String[] args) {

        dataInfo();
    }

    public static void dataInfo() {

        Scanner sc = new Scanner(System.in);

        System.out.print("请输入用户名:");

        String user_Name = sc.nextLine();

        System.out.print("请输入密码:");

        String user_password = sc.nextLine();

        Connection conn = null;

        Statement stat = null;

        ResultSet rs = null;

        String url = "jdbc:mysql://127.0.0.1:3306/cgb2111?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";

        String userName = "账号";

        String password = "密码";

        try {

            Class.forName("com.mysql.cj.jdbc.Driver");

            conn = DriverManager.getConnection(url, userName, password);

            String sql = "select `id`, `name`, `pwd` from `user` where `name` = ? and `pwd` = ? ";

            conn = JarDriver.getConnection();

            ppst = conn.prepareStatement(sql);

            ppst.setString(1, userName);

            ppst.setString(2, userPassword);

            rs = ppst.executeQuery();

            if (rs.next()) {

                System.out.println("恭喜您,登录成功");

            } else {

                System.out.println("用户名或者密码错误");
            }

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (SQLException throwables) {

            throwables.printStackTrace();

        } finally {

            try {
                if (rs != null && rs.isClosed() == false){
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {

                if (stat != null && rs.isClosed() == false){

                    stat.close();
                }
            } catch (SQLException e) {

                e.printStackTrace();
            }

            try {

                if (conn != null && conn.isClosed() == false){

                    conn.close();
                }

            } catch (SQLException e) {

                e.printStackTrace();
            }
        }
    }
}

【运行结果】:
请输入用户名:赵敏' #
请输入密码:
用户名或者密码错误

封装数据库连接代码和释放资源代码

对于多次使用的JDBC与数据库连接的代码和释放资源的方法,我们可以采用封装的方法。这样只要编写一次,以后要使用时,直接调用封装的方法即可。这样可以节省我们大量的开发时间和提高开发效率。

封装代码的步骤:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JarDriver {

    
    public static Connection getConnection() throws ClassNotFoundException, SQLException {

        Class.forName("com.mysql.cj.jdbc.Driver");
        String url = "jdbc:mysql://127.0.0.1:3306/cgb2111?characterEndcoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&allowPublicKeyRetrieval=true";
        String userName = "账号";
        String password = "密码";
        Connection conn = DriverManager.getConnection(url, userName, password);
        return conn;
    }

    
    public static void close(Connection conn, PreparedStatement preps, ResultSet rs) {

        try {

            if (rs != null && rs.isClosed() == false){

                rs.close();

                System.out.println("ResultSet连接已经关闭");
            }

        } catch (SQLException e) {

            e.printStackTrace();
        }

        try {

            if (preps != null && preps.isClosed() == false){

                preps.close();

                System.out.println("PreparedStatement连接已经关闭");
            }

        } catch (SQLException e){

            e.printStackTrace();
        }

        try {

            if (conn != null && conn.isClosed() == false) {

                conn.close();

                System.out.println("Connection连接已经关闭");

            }

        } catch (SQLException e) {

            e.printStackTrace();
        }
    }

    
    public static void close(Connection conn, PreparedStatement preps) {

        try {

            if (preps != null && preps.isClosed() == false){

                preps.close();

                System.out.println("PreparedStatement连接已经关闭");
            }

        } catch (SQLException e){

            e.printStackTrace();
        }

        try {

            if (conn != null && conn.isClosed() == false) {

                conn.close();

                System.out.println("Connection连接已经关闭");

            }

        } catch (SQLException e) {

            e.printStackTrace();
        }
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5696012.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存