• mybatis防注入


    1.SQL防注入

    mybatis语句中要使用 #{xxx}防止SQL注入,${xxx}只是简单替换占位符,有注入的风险

    例子:

    1.1

    "getNameByUserId" resultType="String"> SELECT name FROM user where id = #{userId}

    可以看到输入的参数是String类型的userId,当我们传入userId="34;drop table user;"后,打印的语句是这样的:

    select name from user where id = ?

    这就得益于mybatis在底层实现时使用预编译语句。数据库在执行该语句时,直接使用预编译的语句,然后用传入的userId替换占位符?就去运行了。不存在先替换占位符?再进行编译的过程,因此SQL注入也就没有了生存的余地了。

    mybatis是如何做到sql预编译的呢?其实框架底层使用的正是PreparedStatement类。PreparedStaement类不但能够避免SQL注入,因为已经预编译,当N次执行同一条sql语句时,节约了(N-1)次的编译时间,从而能够提高效率。

    【底层实现原理】

          其原因就是:采用了JDBC的PreparedStatement,就会将sql语句:“select id,no from user where id =?” 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该SQL语句的语法结构了,因为语法分析已经完成了,而语法分析主要是分析sql命令,比如select,from,where,and,or,order by等等。所以即使你后面输入了这些sql命令,也不会被当成sql命令来执行了,因为这些SQL命令的执行,必须先得通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为SQL命令来执行的,只会被当做字符串字面值参数。所以的sql语句预编译可以防御SQL注入。而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。

    1.2

    如果将上面的语句改成:

    "getNameByUserId" resultType="String"> SELECT name FROM user where id = ${userId}  -- 注意与1.1的对比

    当我们输入userId="34;drop table user;"后,打印的语句是这样的:

    select name from user where id = 34;drop table user;

    mybatis没有使用预编译语句,它会先进行字符串拼接再执行编译,这个过程正是SQL注入生效的过程。

    在MyBatis中,“ $ {xxx}”这样格式的参数会直接参与SQL 编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用$ {xxx}“这样的参数格式。所以,这样的参数需要我们在代码中手工进行处理来防止注入。

    #{}:相当于JDBC中的PreparedStatement的

    $ {}:是输出变量的值

    简单说,

    # {}是经过预编译的,是安全的 ; 

    $ {}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入。

  • 相关阅读:
    再有人说synchronized是重量级锁,就把这篇文章扔给他看
    2024最新计算机设计大赛选题推荐
    AI学习路线
    机器学习笔记之最优化理论与方法(五)凸优化问题(上)
    【HarmonyOS】【JAVA UI】鸿蒙怎么对图片编码为base64和base64解码为PixelMap,并显示在控件上
    JS本地存储技术
    Linux 进程调度通知机制
    【408复习】在b站开播通知
    Vue/Vuex (actions) 核心概念 使用方法、辅助函数 mapActions使用方法说明
    Matlab创建文字云
  • 原文地址:https://blog.csdn.net/whupanyinghua/article/details/131147106