纯css打造立体时钟
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
By_jie

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();// 以\n作为一行的标识来读取一行
        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。

posted @ 2018-12-05 23:53  1024军团  阅读(315)  评论(0编辑  收藏  举报