zoukankan      html  css  js  c++  java
  • SQL攻击-预编译--缓存

    PreparedStatement

    它是Statement接口的子接口;

    l 强大之处:

    • SQL攻击;
    • 提高代码的可读性、可维护性;
    • 提高效率!

    学习PreparedStatement的用法:

    • 如何得到PreparedStatement对象:

    ¨ 给出SQL模板!

    ¨ 调用ConnectionPreparedStatement prepareStatement(String sql模板)

    ¨ 调用pstmtsetXxx()系列方法sql模板中的?赋值!

    ¨ 调用pstmtexecuteUpdate()executeQuery(),但它的方法都没有参数。

    l 预处理的原理

    • 服务器的工作:

    ¨ 校验sql语句的语法!

    ¨ 编译:一个与函数相似的东西!

    ¨ 执行:调用函数

    • PreparedStatement

    ¨ 前提:连接的数据库必须支持预处理!几乎没有不支持的!

    ¨ 每个pstmt都与一个sql模板绑定在一起,先把sql模板给数据库,数据库先进行校验,再进行编译。执行时只是把参数传递过去而已!

    ¨ 若二次执行时,就不用再次校验语法,也不用再次编译!直接执行!

     1 什么是SQL攻击

    在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语句的片段!

    2 演示SQL攻击

    首先我们需要创建一张用户表,用来存储用户的信息。

    CREATE TABLE user(

    uidCHAR(32) PRIMARY KEY,

    usernameVARCHAR(30) UNIQUE KEY NOT NULL,

    PASSWORD VARCHAR(30)

    );

    INSERT INTO user VALUES('U_1001', 'zs', 'zs');

    SELECT * FROM user;

    现在用户表中只有一行记录,就是zs

    下面我们写一个login()方法!

    public void login(String username, String password) {

    Connection con = null;

    Statement stmt = null;

    ResultSet rs = null;

    try {

    con = JdbcUtils.getConnection();

    stmt = con.createStatement();

    String sql = "SELECT * FROM user WHERE " +

    "username='" + username +

    "' and password='" + password + "'";

    rs = stmt.executeQuery(sql);

    if(rs.next()) {

    System.out.println("欢迎" + rs.getString("username"));

    } else {

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

    }

    } catch (Exception e) {

    throw new RuntimeException(e);

    } finally {

    JdbcUtils.close(con, stmt, rs);

    }

    }

    下面是调用这个方法的代码:

    login("a' or 'a'='a", "a' or 'a'='a");

    这行当前会使我们登录成功!因为是输入的用户名和密码是SQL语句片段,最终与我们的login()方法中的SQL语句组合在一起!我们来看看组合在一起的SQL语句:

    SELECT * FROM tab_user WHERE username='a' or 'a'='a' and password='a' or 'a'='a'

     3 防止SQL攻击

    l 过滤用户输入的数据中是否包含非法字符;

    l 分步交验!先使用用户名来查询用户,如果查找到了,再比较密码;

    使用PreparedStatement 

    4 PreparedStatement是什么?

    PreparedStatement叫预编译声明!

    PreparedStatementStatement的子接口,你可以使用PreparedStatement来替换Statement

    PreparedStatement的好处:

    防止SQL攻击;

    l 提高代码的可读性,以可维护性;

    l 提高效率。

    5 PreparedStatement的使用

    使用ConnectionprepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;

    调用PreparedStatementsetXXX()系列方法为问号设置值

    调用executeUpdate()executeQuery()方法,但要注意,调用没有参数的方法;

    String sql = “select * from tab_student where s_number=?”;

    PreparedStatement pstmt = con.prepareStatement(sql);

    pstmt.setString(1, “S_1001”);

    ResultSet rs = pstmt.executeQuery();

    rs.close();

    pstmt.clearParameters();

    pstmt.setString(1, “S_1002”);

    rs = pstmt.executeQuery();

    在使用Connection创建PreparedStatement对象时需要给出一个SQL模板,所谓SQL模板就是有“?”的SQL语句,其中“?”就是参数。

    在得到PreparedStatement对象后,调用它的setXXX()方法为“?”赋值,这样就可以得到把模板变成一条完整的SQL语句,然后再调用PreparedStatement对象的executeQuery()方法获取ResultSet对象。

    注意PreparedStatement对象独有的executeQuery()方法是没有参数的,而StatementexecuteQuery()是需要参数(SQL语句)的。因为在创建PreparedStatement对象时已经让它与一条SQL模板绑定在一起了,所以在调用它的executeQuery()executeUpdate()方法时就不再需要参数了。

    PreparedStatement最大的好处就是在于重复使用同一模板,给予其不同的参数来重复的使用它。这才是真正提高效率的原因。 

    所以,建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement

    useServerPrepStmts参数

    默认使用PreparedStatement是不能执行预编译的,这需要在url中给出useServerPrepStmts=true参数(MySQL Server 4.1之前的版本是不支持预编译的,而Connector/J在5.0.5以后的版本,默认是没有开启预编译功能的)。

    例如:jdbc:mysql://localhost:3306/test?useServerPrepStmts=true

      这样才能保证mysql驱动会先把SQL语句发送给服务器进行预编译,然后在执行executeQuery()时只是把参数发送给服务器。

    cachePrepStmts参数

    当使用不同的PreparedStatement对象来执行相同的SQL语句时,还是会出现编译两次的现象,这是因为驱动没有缓存编译后的函数key,导致二次编译。如果希望缓存编译后函数的key,那么就要设置cachePrepStmts参数为true。例如:

    jdbc:mysql://localhost:3306/test?useServerPrepStmts=true&cachePrepStmts=true

  • 相关阅读:
    27 Spring Cloud Feign整合Hystrix实现容错处理
    26 Spring Cloud使用Hystrix实现容错处理
    25 Spring Cloud Hystrix缓存与合并请求
    24 Spring Cloud Hystrix资源隔离策略(线程、信号量)
    23 Spring Cloud Hystrix(熔断器)介绍及使用
    22 Spring Cloud Feign的自定义配置及使用
    21 Spring Cloud使用Feign调用服务接口
    20 Spring Cloud Ribbon配置详解
    19 Spring Cloud Ribbon自定义负载均衡策略
    18 Spring Cloud Ribbon负载均衡策略介绍
  • 原文地址:https://www.cnblogs.com/rogge7/p/7002592.html
Copyright © 2011-2022 走看看