防止sql注入(java防止sql注入)

在实际操作过程中如何避免出现SQL注入漏洞

本文将针对开发过程中依旧经常出现的SQL编码缺陷,讲解其背后原理及形成原因。并以几个常见漏洞存在形式,提醒技术同学注意相关问题。最后会根据原理,提供解决或缓解方案。

二 SQL注入漏洞的原理、形成原因

SQL注入漏洞,根本上讲,是由于错把外部输入当作SQL代码去执行。目前最佳的解决方案就是预编译的方式。

SQL语句在执行过程中,需要经过以下三大基本步骤:

  1. 代码语义分析
  2. 制定执行计划
  3. 获得返回结果

而一个SQL语句是由代码和数据两部分,如:

SELECT id, name, phone FROM userTable WHERE name = ‘xiaoming’;

SELECT id, name, phone FROM userTable WHERE name = 是代码,’xiaoming’是数据。

而预编译,以Mybatis为例,就是预先分析带有占位符的语义:

如SELECT id, name, phone FROM userTable WHERE id = #{name};

然后再将数据’xiaoming’,传入到占位符。这样一来,错开来代码语义分析阶段,也就不会被误认为是代码的一部分了。

在最早期,开发者显式使用JDBC来自己创建Connection,执行SQL语句。这种情况下,如果将外部可控数据拼接到SQL语句,且没有做充分过滤的话,就会产生漏洞。这种情况在正常的业务开发过程中已经很少了,按照公司规定,无特殊情况下,必须使用ORM框架来执行SQL。

但目前部分项目中,仍会使用JDBC来编写一些工具脚本,如DataMerge.java 、DatabaseClean.java,借用JDBC的灵活性,通过这些脚本来执行数据库批量操作。

此类代码不应该出现在线上版本中,以免因各种情况,被外部调用。

三 直接使用Mybatis

1 易错点

目前大部分的平台代码是基于Mybatis来处理持久层和数据库之间的交互的,Mybatis传入数据有两种占位符 {} 和 #{} 。 {}和#{}。 {}可以理解为语义分析前的字符串拼接,讲传入的参数,原封不动地传入。

比如说

SELECT id, name, phone FROM userTable WHERE name = ‘${name}’;

传入name=xiaoming后,相当于

SELECT id, name, phone FROM userTable WHERE name = ‘xiaoming’;

实际应用中

SELECT id, name, phone FROM userTable WHERE ${col} = ‘xiaoming’;

传入col = “name”,相当于

SELECT id, name, phone FROM userTable WHERE name = ‘xiaoming’;

就像预编译原理介绍里讲的一样,使用#{} 占位符就不存在注入问题了。但有些业务场景是不可以直接使用#{}的。

比如order by语法中

如果编写SELECT id, name, phone FROM userTable ORDER BY #{}; ,执行时是会报错的。因为order by后的内容,是一个列名,属于代码语义的一部分。如果在语义分析部分没有确定下来,就相当于执行SELECT id, name, phone FROM userTable ORDER BY 。肯定会有语法错误。

再比如like场景下

SELECT id, name, phone FROM userTable WHERE name like ‘%#{name}%’;

#{}不会被解析,从而导致报错。

in 语法和 between语法都是如此,那么如何解决这类问题呢?

2 正确写法

order by(group by)语句中使用${}

  1. 使用条件判断
<select resultType="Emp" parameterType="Emp">



    select * from users where id < #{id}



    <choose>



        <when test="order == \"name\"">



            order by name



        </when>



        <when test="order != \"age\"">



            order by age



        </when>



        <otherwise>



            order by id



        </otherwise>



    </choose>



</select>

2. 使用全局过滤机制,限制order by后的变量内容只能是数字、字母、下划线。

如使用正则过滤:

keyword = keyword.replaceAll("[^a-zA-Z0-9_\s+]", "");

这里需要注意,过滤需要使用白名单,不能使用黑名单,黑名单无法解决注入问题。

LIKE语句

由于需要like中的关键词需要包裹在两个%符号中,因此可以使用CONCAT函数进行拼接。

<select resultMap="studentMap">



    SELECT *



    FROM student



    WHERE student.stu_name



            LIKE CONCAT('%',#{stuName},'%')



</select>

注意不要用 CONCAT(‘%’,’${stuName}’,’%’) ,这样仍然存在漏洞。也就是说,使用$符号是不对的,使用#符号才安全。

IN语句

类似于like语句,直接使用#{}会报错,常见的错误写法为:

tenant_id in (${tenantIds})

正确的写法为:

select * from news where id in



<foreach collection="ids" item="item" open="("separator="," close=")">#{item}</foreach>

四 Mybatis-generator使用安全

繁重的CRUD代码压力下,开发者慢慢开始通过Mybatis-generator、idea-mybatis-generator插件、通用Mapper、Mybatis-generator-plus来自动生成Mapper、POJO、Dao等文件。

这些工具可以自动的生成CRUD所需要的文件,但如果使用不当,就会自动产生SQL注入漏洞。我们以最常用的org.mybatis.generator为例,来讲解可能会出现的问题。

1 动态语句支持

Mybatis-generator提供来一些函数,帮助用户把SQL的各个条件连接起来,比如多个参数的like语法,多个参数的比较语法。为了保证使用的简洁性,需要使用 将 一 写 语 一 待 码 拼 接 到 S Q L 语 句 中 。 而 如 果 开 发 者 诗 用 不 当 , 将 外 不 输 入 也 传 入 了 {}占位符。就会产生漏洞。

2 targetRuntime参数配置

在配置generator时,配置文件generator-rds.xml中有一个targetRuntime属性,默认为MyBatis3。在这种情况下,会启动Mybatis的动态语句支持,启动enableSelectByExample、enableDeleteByExample、enableCountByExample 以及 enableUpdateByExample功能。

以enableSelectByExample为例,会在xml映射文件中代入以下动态模块:

  <sql >



    <where >



      <foreach collection="oredCriteria" item="criteria" separator="or" >



        <if test="criteria.valid" >



          <trim prefix="(" suffix=")" prefixOverrides="and" >



            <foreach collection="criteria.criteria" item="criterion" >



              <choose >



                <when test="criterion.noValue" >



                  and ${criterion.condition}



                </when>



                <when test="criterion.singleValue" >



                  and ${criterion.condition} #{criterion.value}



                </when>



                <when test="criterion.betweenValue" >



                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}



                </when>



                <when test="criterion.listValue" >



                  and ${criterion.condition}



                  <foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >



                    #{listItem}



                  </foreach>



                </when>



              </choose>



            </foreach>



          </trim>



        </if>



      </foreach>



    </where>



  </sql>

开发者include该模块就可以添加where条件,但如果使用不当,就会导致SQL注入漏洞:

<select resultMap="BaseResultMap" parameterType="com.doctor.mybatisdemo.domain.userExample" >



    select



    <if test="distinct" >



      distinct



    </if>



    <include refid="Base_Column_List" />



    from user



    <if test="_parameter != null" >



      <include refid="Example_Where_Clause" />



    </if>



    <if test="orderByClause != null" >



      order by ${orderByClause}



    </if>



  </select>

并使用自定义的参数添加函数:

public Criteria addKeywordTo(String keyword) {



  StringBuilder sb = new StringBuilder();



  sb.append("(display_name like '%" + keyword + "%' or ");



  sb.append("org like '" + keyword + "%' or ");



  sb.append("status like '%" + keyword + "%' or ");



  sb.append("id like '" + keyword + "%') ");



  addCriterion(sb.toString());



  return (Criteria) this;



}

目的是为了实现同时对display_name、org、status、id的like操作。其中addCriterion是Mybatis-generator自带的函数:

protected void addCriterion(String condition) {



    if (condition == null) {



        throw new RuntimeException("Value for condition cannot be null");



    }



    criteria.add(new Criterion(condition));



}

这里的误区在于,addCriterion本身提供了多个条件的支持,但开发者认为需要自己把多个条件拼接起来,一同传入addCriterion方法。如同案例中的代码一样,最终传入addCriterion的只有一个参数。从而执行Example_Where_Clause语句中的:

<when test="criterion.noValue" >



    and ${criterion.condition}



</when>

也就是说,开发者把自己拼接的SQL语句,直接代入了${criterion.condition}中,从而导致了漏洞的产生。

而按照Mybatis-generator的文档,正确的写法应该是:

public void addKeywordTo(String keyword, UserExample userExample) {



  userExample.or().andDisplayNameLike("%" + keyword + "%");



  userExample.or().andOrgLike(keyword + "%");



  userExample.or().andStatusLike("%" + keyword + "%");



  userExample.or().andIdLike("%" + keyword + "%");



}

or方法负责创建Criteria,这时触发的逻辑就是

<when test="criterion.singleValue" >



  and ${criterion.condition} #{criterion.value}



</when>

${criterion.condition}被替换为了没有单引号的like,like作为语义代码,在语义分析前拼接到了SQL语句中,而 “%” + keyword + “%” 会作为数据添加到预编译#{criterion.value}中去,从而避免了注入。

类似的,也提供了In语法的安全使用方法:

  List<Integer> field5Values = new ArrayList<Integer>();



  field5Values.add(8);



  field5Values.add(11);



  field5Values.add(14);



  field5Values.add(22);









  example.or()



    .andField5In(field5Values);

Beetween的安全使用方法:

  example.or()



    .andField6Between(3, 7);

Mybatis-generator默认生成的order by语句也是使用${}直接进行拼接的:

<if test="orderByClause != null" >



      order by ${orderByClause}



    </if>

如果没有对传入的参数进行额外的过滤的话,就会导致注入问题。

3 order by

除了自己写的SQL语句以外,Mybatis-generator默认生成的order by语句也是使用${}直接进行拼接的:

<if test="orderByClause != null" >



      order by ${orderByClause}



    </if>

如果没有对传入的参数进行额外的过滤的话,就会导致注入问题。

PS: 实际扫雷过程中发现很多语句自动生成了order by语法,但上层调用时,并没有传入该可选参数。这种情况应当删除多余的order by语法。

4 其它插件

插件与插件之间的安全缺陷还不太一样,下面简单列举了常用的几种插件。

idea-mybatis-generator

这是IDEA的插件,可以在开发过程中,从IDE的层面,自动生成CRUD中需要的文件。使用该插件时,也有一些默认安全隐患需要注意。

1)自定义order by处理

like\in\between可以参照官方文档使用,无安全隐患。

但该插件没有内置的order by处理,需要自行编写,编写时,参考Case2

2)默认的IF条件前需要判断是否为空

插件默认生成的语法大致如下:

<if test=”ID != null”>

ID

= #{ID} and

当ID参数为null时,if标签下的逻辑不会添加到SQL语句中,可能会导致DOS、权限绕过等漏洞。因此,参数传入查询语句前,需要确认不为空。

com.baomidou.mybatis-plus

1. apply方法传参时,应当使用{}

2. 自带的last方法,其原理是直接拼接到SQL语句的末尾,存在注入漏洞。

五 其它ORM框架

1 Hibernate

ORM全称为对象关系映射(Object Relational Mapping),简单地说,就是将数据库中的表映射为Java对象, 这种只有属性,没有业务逻辑的对象也叫做POJO(Plain Ordinary Java Object)对象。

Hibernate是第一个被广泛使用的ORM框架,它通过XML管理数据库连接,提供全表映射模型,封装程度很高。在配置映射文件和数据库链接文件后,Hibernate就可以通过Session对象进行数据库操作,开发者无需接触SQL语句,只需要写HQL语句即可。

Hibernate经常与Struts、Spring搭配使用,也就是Java世界的经典SSH框架。

HQL相较于SQL,多了很多语法限制:

1. 不能查询未做映射的表,只有当模型之间的关系明确后,才可以使用UNION语法。

2. 表名,别名大小写敏感。

3. 没有 * 、 # 、 — 。

4. 没有延时函数。

所以HQL注入利用要比SQL注入苦难得多。从代码审计的角度和普通SQL注入是一致的:

拼接会导致注入漏洞:

List<Student> studentList = session.createQuery("FROM Student s WHERE s.stuId = " + stuId).list();

可以使用占位符和具名参数来防止SQL语句,其本质都是预编译。

List<Student> studentList = session.createQuery("FROM Student s WHERE s.stuId = :stuId").setParameter("stuId",stuId).list();
List<Student> studentList = session.createQuery("FROM Student s WHERE s.stuId = ?").setParameter(stuId).list();

Hibernate在使用过程中有很多不足:

1. 全表映射不灵活,更新时需要发送所有字段,影响程序运行效率。

2. 对复杂查询的支持很差。

3. 对存储过程的支持很差。

4. HQL性能较差,无法根据SQL进行优化。

在审计Hibernate相关注入时,可以通过全局搜索createQuery来快速定位SQL操作的位置。

2 JPA

JPA全称为Java Persistence API,是Java EE提供的一种数据持久化的规范,允许开发者通过XML或注解的方式,将某个对象,持久化到数据库中。

主要包括三方面内容:

1. ORM映射元数据,通过XML或注解,描述对象和数据表之间的对应关系。框架便可以自动将对象中的数据保存到数据库中。

常见的注解有:@Entity、@Table、@Column、@Transient

2. 数据操作API,内置接口,方便对某个数据表执行CRUD操作,节省开发者编写SQL的时间。

常见的方法有:entityManager.merge(T t);

3. JPQL, 提供一种面向对象而不是面向数据库的查询语言,将程序和数据库、SQL解耦合。

JPA是一套规范,Hibernate实现了这一JPA规范。

在Spring框架中,提供了简易版的JPA实现——spirng data jpa。按照约定好的方法命名规则写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD之外的功能,如分页、排序、复杂查询等等。使用起来更简单,但底层仍然在使用Hibernate的JPA实现。

和HQL注入一样,如果使用拼接的方式,将用户可控的数据代入了查询语句中,就会导致SQL注入。

安全的查询应该使用预编译技术。

Spring Data JPA的预编译写法为:

String getUser = "SELECT username FROM users WHERE id = ?";



Query query = em.createNativeQuery(getUser);



query.setParameter(1, id);



String username = query.getResultList();

小贴士:其实Hibernate的出现日期比JPA规范要早,Hibernate逐渐成熟之后,JavaEE的开发团队,邀请Hibernate核心开发人员一起制定了JPA规范。之后Spring Data JPA按照规范做了进一步优化。除此之外,JPA规范的实现有很多产品,比如Eclipse的TopLink(OracleLink)。

六 总结

经过上面的介绍,尤其是围绕Mybatis易错点的讨论,我们可以得到以下结论:

1. 持久层组件种类繁多。

2. 开发者对工具使用的错误理解,是漏洞出现的主要原因。

3. 由于自动生成插件的动态特性,自动化发现SQL漏洞不能简单地使用${}来寻找。 必须要根据全局的持久层组件特性,来做详细的匹配规则。

参考链接:

????????

PostgreSQL实战进阶

PostgreSQL被誉为“世界上功能最强大的开源数据库”,是以加州大学伯克利分校计算机系开发的POSTGRES 4.2为基础的对象关系型数据库管理系统。

PostgreSQL支持大部分 SQL标准并且提供了许多其他现代特性:复杂查询、外键、触发器、视图、事务完整性、MVCC。 同样,PostgreSQL 可以用许多方法扩展,比如,通过增加新的数据类型、函数、操作符、聚集函数、索引。 开发者可以免费使用、修改、和分发 PostgreSQL,不管是私用、商用、还是学术研究使用。

如果您觉得文章对您有帮助,可以点赞评论转发支持一下~蟹蟹!

原文链接:https://www.tuicool.com/articles/vuMRfeb

本文来自投稿,不代表展天博客立场,如若转载,请注明出处:https://www.me900.com/61847.html

赞 (0)

相关推荐

  • 玉泉东农贸市场,玉泉东农贸市场地址位置

    6月13日,在北京市新型冠状病毒肺炎疫情防控工作第114场新闻发布会上,北京市疾控中心副主任庞星火通报,在海淀一农贸市场中发现1例咽拭子阳性样本,是1例新发地确诊病例的密切接触者。 这家农贸市场在哪儿?北京青年报记者了解到,海淀区市场监督管理局、海淀区卫生健康委联合发布刚刚《关于玉泉东商品交易市场暂时休市的公告》。公告称,近日,在新冠病例密切接触者排查工作中…

    2023-04-24
  • 想找个兼职晚上7点到12点,在家就能做的副业兼职

      靠兼职写作在工作之余获得收入,是一个门槛较低又比较有发展的选择。 那么,为什么写作、写小说这件事和“晚上兼职做的工作”有关系呢? 很简单,夜深人静的晚上往往是独处的时间,这种“沉浸式”的状态下人的注意力更容易凝聚,在没有干扰项的时候更容易写出更好的东西来,自然更适合写作。 除此之外,写作可以将碎片化的时间利用起来。坐地铁的时候可以在备忘录里写构…

    2022-06-06
  • 卡姆容留他人吸毒案今日开庭(破获容留他人吸毒案)

    今天下午 脱口秀演员卡姆容留他人吸毒案 在上海市虹口区人民法院 一审公开开庭审理 法院当庭判决 以容留他人吸食毒品罪 判处卡姆有期徒刑8个月 因容留他人吸食大麻被起诉 今年25岁的卡姆本名艾力卡木·阿斯克尔,是笑果文化旗下艺人,因《奇葩说》《脱口秀大会》《吐槽大会》被人熟知,还曾夺得第二季《脱口秀大会》冠军,并以固定卡司身份参与喜剧脱口秀节目《吐槽大会第四季…

    2023-05-28
  • 电动车排行,十大电动车排名

    《电动车排行:深入探究与分析》 一、品牌影响力与市场份额 在电动车排行中,品牌影响力无疑是一个重要的考量因素。 一些知名品牌,如特斯拉、比亚迪等,它们在全球范围内都拥有较高的知名度和市场份额。 特斯拉以其先进的电池技术和创新的设计理念,吸引了众多消费者的关注,其电动车在性能和续航方面表现出色,可能会成为很多消费者的首选。 比亚迪则凭借着在电池领域的深厚积累和…

    2025-04-29
  • 比较好玩的免费网游,steam平台好玩的免费网游排行榜

    比较好玩的免费网游,steam平台好玩的免费网游排行榜比较好玩的免费网游,steam平台好玩的免费网游排行榜比较好玩的免费网游,steam平台好玩的免费网游排行榜比较好玩的免费网游,steam平台好玩的免费网游排行榜

    steam平台,中文也就是蒸汽平台,上面积累了海量游戏,不管是单机游戏,独立游戏,还是网络游戏,都应有尽有,那么本期就为大家盘点Steam平台上,那些最良心的免费射击网,相信大部分人都玩过。   《战争前线》 最早该游戏就有国服版,不过效果不佳,最后停运。Steam上的是国际服,世界各地任何一个玩家都可以进入体验。虽然它是2011年的经典网游,但画…

    2022-04-17 • 投稿
  • 轻音乐欣赏放松心情纯音乐有哪些

    在这喧嚣的世界里,我们常常被忙碌与压力所紧紧包围,我们的心灵渴望一片宁静的绿洲。放松心情,让内心回归宁静,成为我们寻求内在平衡和幸福的重要方式。 放松心情也可以通过与大自然亲近来实现。大自然是最美妙的艺术家,她的美丽和纯净让我们忘却烦恼和焦虑。我们可以选择去花园散步,感受花香和清新的空气。我们可以去海边听波涛汹涌的声音,沐浴在阳光的温暖中。我们可以去森林徜徉…

    2023-06-16
  • 红糖面膜一周做几次,红糖面膜的功效与作用

    红糖面膜一周做几次,红糖面膜的功效与作用红糖面膜一周做几次,红糖面膜的功效与作用红糖面膜一周做几次,红糖面膜的功效与作用红糖面膜一周做几次,红糖面膜的功效与作用

    糖在我们生活中如同一把双刃剑,一方面是为人体提供能量的主要物质之一,同时还在菜肴中起到调味增鲜的作用;另一方面如果过量摄入,有可能成为诱发许多疾病的“罪魁祸首”。然而不少人以为那是白糖的事,与红糖无关,在他们的认知中,红糖是滋补养生的“营养糖”。 综观各个市场和超市,我们很快发现一个普遍现象,红糖价格远远高于白糖,我国红糖最主要产区广西,大多数农家都会手工制…

    2023-07-12 • 投稿
  • 罪恶都市任务攻略,侠盗飞车罪恶都市任务列表

    1.Four Lron 在工地与Carrington交谈,将要去干掉一个爱打高尔夫的工头。先去衣店换一身高尔夫装(真难看)后去高尔夫球场,由于无 法将武器带入高尔夫球场,只得用高尔夫球棒了。开小车那个工头练球的地方,先上去放到一个守楼梯的保镖,然后下楼 (不要和其他保镖纠缠)将上车逃跑的工头干掉。或者直接回到高尔夫球场大门口等他自投罗网。 报酬:500 2.…

    2023-07-10
  • 早期征兆说明你怀孕,8个征兆说明你怀孕了

    早期征兆说明你怀孕,8个征兆说明你怀孕了早期征兆说明你怀孕,8个征兆说明你怀孕了早期征兆说明你怀孕,8个征兆说明你怀孕了早期征兆说明你怀孕,8个征兆说明你怀孕了

    妈妈群里有一个刚结婚不久的女生,这几天,这位小美女老是说自己像是感冒了一样,浑身提不起劲,也不爱吃东西,打算去医生那开点感冒药,又怕影响备孕。群里有一个宝妈提醒她:该不是怀孕了吧?   于是小美女就去医院检查,结果真的是:怀!孕!了! 大家都挺为她开心的, 也不枉费辛苦了这几个月,纷纷为她支招去对应孕早期。 因为接下来这会准妈妈将会出现一系列的早孕…

    2022-04-20 • 投稿
  • dnf副职业哪个好(Dnf副职业哪个好)

    dnf副职业哪个好(Dnf副职业哪个好)dnf副职业哪个好(Dnf副职业哪个好)dnf副职业哪个好(Dnf副职业哪个好)dnf副职业哪个好(Dnf副职业哪个好)

    各位dnf勇士们大家好,不少新手玩家不知dnf副职业有什么作用,本期我们就来介绍一下dnf4大副职业的作用! 1.分解师 蓝白装可以分解出对应灵魂及各色晶体,有几率产生暴击,产生大量有色晶体,无色产量丰厚。 紫装分解得到稀有灵魂及微量无色和下级元素,除想要稀有灵魂,紫装不建议分解机分解。 2.炼金师 能够制作打团时必备药物,例如斗神,精神刺激,顶级力量药之类…

    2022-01-20 • 投稿
  • 怎样申请公费留学(怎样申请国家公费留学)

    视觉中国 图 今年1月以来,国家留学网先后发布了关于启动2023年度赴日本、俄罗斯、韩国相关公派留学项目遴选工作的通知。从2月初开始,这些项目的申请人经所在学校(或单位)审核同意后,可进行网上报名。留学期间,留学目的国免学费(或提供奖学金),并且留学人员可获得留学目的国(或国家留学基金)提供的奖学金(补贴)及一次往返国际旅费。 其中,2023年度中俄政府奖学…

    2023-05-31
  • 思埠官网,微商大佬思埠吴召国涉嫌传销被查

    思埠官网,微商大佬思埠吴召国涉嫌传销被查思埠官网,微商大佬思埠吴召国涉嫌传销被查思埠官网,微商大佬思埠吴召国涉嫌传销被查思埠官网,微商大佬思埠吴召国涉嫌传销被查

    继张庭林瑞阳公司后,又一个微商大佬涉嫌传销被查。   据媒体报道,广东思埠集团与王老吉品牌合作推出的“哔嗨啤”啤酒项目因涉嫌传销,被河南省获嘉县市场监管局向当地申请冻结7家关联公司账户,经法院裁定冻结资金额度达2亿元。   获嘉县市场监管局相关办案负责人表示,他们是在接到相关举报后,对“哔嗨啤”项目涉嫌传销展开调查,相关资金已经冻结,思埠…

    2022-04-22 • 投稿