• dljd_(013_014)_使用PreparedStatement避免SQL注入攻击


    一、使用PreparedStatement来避免SQL注入攻击示例

      这里我只提供源码、测试类及结果截图信息、建库/表的语句详见上一集

    package edu.aeon.logon;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    
    import edu.aeon.aeonutils.AeonJdbcUtils;
    
    /**
     * [说明]:实现用户登录、并且演示sql注入攻击 造成sql注入攻击的原因
     * 1.and和or的优先级(and(可以理解为并且)优先与or(可以理解为或者))其实是构造or的条件来无视and条件 
     * 2.sql语句的拼接
     * 如何解决sql注入攻击? 数据库and 和 or的优先级天生的、我们无法改变 唯一解决思路:
     * 我们用预编译的PreparedStatement来执行sql语句、这种方式不会去拼接sql语句的
     * @author aeon
     *
     */
    public class UserLogon {
        /**
         * 封装键盘输入
         * 
         * @return
         */
        public static Map<String, String> ReadBoard() {
            /**
             * 键盘扫描器:扫描键盘输入的内容
             */
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String username = scanner.nextLine();// 以
    作为一行的标识来读取一行
            System.out.println("请输入密码:");
            String password = scanner.nextLine();
            Map<String, String> userMap = new HashMap<String, String>();
            // 将键盘输入的内容封装到map集合中、并且返回给调用者
            userMap.put("username", username);
            userMap.put("password", password);
            return userMap;
        }
    
        /**
         * 用户登录具体实现
         * 
         * @return 登录成功标志 true则登录成功、否则失败!
         */
        public static boolean userLogon() {
            boolean flag = false;
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            try {
                // 连接数据库
                connection = AeonJdbcUtils.getMySqlConnection();
                // 获取到用户输入的数据
                Map<String, String> userMap = ReadBoard();
                // 登录sql 这里sql语句要设置的内容、不管什么类型,统统用?占位符
                String logonSql = "select * from user where username=? and userpw =?";
                // 将sql语句预编译到PreparedStatement对象当中
                preparedStatement = connection.prepareStatement(logonSql);
                preparedStatement.setString(1, userMap.get("username"));
                preparedStatement.setString(2, userMap.get("password"));
                System.out.println(logonSql);
                // 因为sql语句已经被编译到PreparedStatement对象中了,所以此处执行再也不需要sql语句
                resultSet = preparedStatement.executeQuery();
                if (resultSet.next()) {
                    flag = true;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                AeonJdbcUtils.closeDB(resultSet, preparedStatement, connection);
            }
            return flag;
        }
    
        /**
         * 用户登录测试
         * 
         * @param args
         */
        public static void main(String[] args) {
            System.out.println(userLogon() ? "用户登录成功!" : "用户登录失败!");
        }
    }

      执行结果截图(我们输入错误的用户名和密码):

      

    执行结果截图(我们输入正确的用户名和相应密码):

      

      执行结果截图(再构造sql注入攻击):

      

    这样我们通过预编译的PreparedStatement执行sql语句来避免了sql注入的攻击。

    二、statement 和PreparedStatement的区别:
      1.statement需要拼接sql语句,会导致sql注入攻击、而PreparedStatement不需要拼接sql语句,从而避免了sql注入攻击。
      2.statement执行多条sql语句的时候都是反复的进行先编译再执行、这样效率低,而PreparedStatement只需编译一次、往后都是执行编译好的sql语句、效率高。
      所以以后我们只使用PreparedStement。

    如有任何疑问可联系邮箱: 给我发邮件、或直接联系QQ:1584875179 || 点返回首页

  • 相关阅读:
    Python中常用的模块(sys模块)
    Python中常用的模块(OS模块)
    Python中常用的模块(time模块)
    Python中常用的模块(random模块)
    Python生成器详解
    Python装饰器详解
    python 两个list 求交集,并集,差集
    数据库中的视图索引
    数据库中的外键和主键理解
    mssql学习
  • 原文地址:https://www.cnblogs.com/aeon/p/10074313.html
Copyright © 2020-2023  润新知