RASP| SQL注入检测与防御
2022-7-30 20:3:12 Author: mp.weixin.qq.com(查看原文) 阅读量:3 收藏

    一方面据映射框架如mybatis、hiberate等在框架底层已经实现了对sql注入的防御,另一方面白盒/黑盒等扫描器也能解决一部分sql注入问题,sql注入的出现风险被大大降低。但是在研发人员未能恰当的使用框架或者sql语句拼接不当的的情况下,仍然可能导致sql注入的风险。本文分析sql注入的几种情况以及RASP在其中的作用。

1.JDBC 拼接不当造成的SQL注入

    JDBC有两种方法执行SQL语句,分别为PrepareStatement和Statement。两个方法的区别在于PrepareStatement会对SQL语句进行预编译,而Statement方法在每次执行时都需要编译,会增大系统开销。理论上PrepareStatement的效率和安全性会比Statement要好,但并不意味着使用PrepareStatement就绝对安全,不会产生SQL注入。

      PrepareStatement方法支持使用‘?’对变量位进行占位,在预编译阶段填入相应的值构造出完整的SQL语句,此时可以避免SQL注入的产生。但开发者有时为了便利,会直接采取拼接的方式构造SQL语句,此时进行预编译则无法阻止SQL注入的产生。如以下代码所示,PrepareStatement虽然进行了预编译,但在以拼接方式构造SQL语句的情况下仍然会产生SQL注入。代码示例如下(若使用“or 1=1”,仍可判断出这段代码存在SQL注入)

String sql = "select * from user where id =" + req.getParameter("id");out.println(sql);try{    PreparedStatement pstt = con.prepareStatement(sql);    ResultSet re = pstt.executeQuery();    while(rs.next()){        out.println("<br>id:"+rs.getObject("id"));        out.println("<br>name:"+re.getObject("name"));    }    catch(SQLException e){        e.printStackTrace();    }}

     正确地使用PrepareStatement可以有效避免SQL注入的产生,使用“?”作为占位符时,填入对应字段的值会进行严格的类型检查。将前面的“拼接构造SQL语句”改为如下“使用占位符构造SQL语句”的代码片段,即可有效避免SQL注入的产生。

PrintWriter out = resp.getWriter();String sql = "select * from user where id = ?"out.println(sql);try{    PreparedStatement pstt = con.prepareStatement(sql);    pstt.setInt(1,Integer.parseInt(req.getParameter("id")));    ResultSet rs = pstt.executeQuery();    // sql执行结果的代码省去....}

2.框架使用不当造成SQL注入

    如今的Java项目或多或少会使用对JDBC进行更抽象封装的持久化框架,如MyBatis和Hibernate。通常,框架底层已经实现了对SQL注入的防御,但在研发人员未能恰当使用框架的情况下,仍然可能存在SQL注入的风险。

Mybatis框架

    MyBatis框架的思想是将SQL语句编入配置文件中,避免SQL语句在Java程序中大量出现,方便后续对SQL语句的修改与配置。MyBatis中使用parameterType向SQL语句传参,在SQL引用传参可以使用#{Parameter}和${Parameter}两种方式

使用#{Parameter}构造SQL的代码如下所示

<select id="getUsername" resultType="com.example.bean.User">    select id,name,age from user where name #{name}<select>

    从Debug回显的SQL语句执行过程可以看出,使用#{Parameter}方式会使用“?”占位进行预编译,因此不存在SQL注入的问题。用户可以尝试构造“name”值为“z1ng or 1=1”进行验证。回显如下,由于程序未查询到结果出现了空指针异常,因此此时不存在SQL注入。

使用${Parameter}构造SQL的代码如下所示:

<select id = "getUsername" resultType = "com.example.bean.User">    select id,name,age from user where name = ${name}<select>

name”值被拼接进SQL语句之中,因此此时存在SQL注入。${Parameter}采用拼接的方式构造SQL,在对用户输入过滤不严格的前提下,此处很可能存在SQL注入。

Hibernate

    Hibernate是一种ORM框架,全称为 Object_Relative DateBase-Mapping,Hibernate框架是Java持久化API(JPA)规范的一种实现方式。Hibernate 将Java 类映射到数据库表中,从 Java 数据类型映射到 SQL 数据类型。Hibernate是目前主流的Java数据库持久化框架,采用Hibernate查询语言(HQL)注入

    HQL的语法与SQL类似,受语法的影响,HQL注入在实际漏洞利用上具有一定的限制。

3.jrasp mysql检测模块

      不同sql client版本,hook类差别大,这里以mysql8.x 为例子说明。

1)可配置参数:

2)sql拼接hook

com.mysql.cj.jdbc.StatementImpl

3)sql 预编译hook

com.mysql.cj.jdbc.ClientPreparedStatement,com.mysql.cj.jdbc.PreparedStatement

4检测算法

4.sql注入实战

存在sql拼接的业务代码如下

正常sql(返回用户自己的数据)

sql注入(返回了全部用户数据)

5.检测与防御

    值得注意的是不同于复杂的正则规则检测, jrasp内置了 sql 注入词法分析防火墙,单条sql检测时间在0.1ms内完成,误报/漏报率极低。

---------------------------------------------------------------------------

🔥🔥🔥国内技术领先的开源RASP社区 https://www.jrasp.com


文章来源: https://mp.weixin.qq.com/s?__biz=Mzg5MjQ1OTkwMg==&mid=2247484458&idx=1&sn=d4d656eb02cbb7fccd0f4b8b785e1da1&chksm=c03c8a3bf74b032d724511c0a1e3a776ab0aad1e26317210bba3db17bdbae21623b8e51b50ee&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh