美文网首页代码审计
【代码审计】SQL 注入

【代码审计】SQL 注入

作者: TeamsSix | 来源:发表于2021-11-17 20:47 被阅读0次

    0x01 JDBC 拼接不当造成 SQL 注入

    JDBC 有两种方法执行 SQL 语句,分别为 PrepareStatement 和 Statement,两个方法的区别在于 PrepareStatement 会对 SQL 语句进行预编译,而 Statement 在每次执行时都需要编译,会增大系统开销。

    理论上 PrepareStatement 的效率和安全性会比 Statement 好,但不意味着就不会存在问题。

    以下是一个使用 Statement 执行 SQL 语句的示例

    String sql = "select * from user where id ="+req.getParameter("id");
    PrintWriter out = resp.getWriter();
    out.println("Statement Demo");
    out.println("SQL: "+sql);
    try {
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery(sql);
    

    这里如果输入的 id 为 1 or 1 = 2,那么 SQL 语句就会被拼接为 select * from user where id = 1 or 1 = 2,改变了想要查询 id = 1 的语义。

    PreqareStatement 方法支持使用 ? 对变量位进行占位,在预编译阶段填入相应的值会构造出完整的 SQL 语句,从而避免 SQL 注入的产生。

    但开发有时为了便利,会直接采取拼接的方式构造 SQL 语句,这样一来依然会存在 SQL 注入,如下代码所示。

    String sql = "select * from user where id ="+req.getParameter("id");
    
    PrintWriter out = resp.getWriter();
    out.println("prepareStatement Demo");
    out.println("SQL: "+sql);
    try {
        PreparedStatement pst = conn.prepareStatement(sql);
        ResultSet rs = pst.executeQuery();
    

    此时如果使用 or 1 = 1 仍然可以判断存在 SQL 注入,但是如果使用 ? 作为占位符,填入的字段的值就会进行严格的类型检查,就可以有效的避免 SQL 注入的产生,如下代码所示。

    PrintWriter out = resp.getWriter();
    out.println("prepareStatement Demo");
    String sql = "select * from user where id = ?";
    out.println(sql);
    try {
        PreparedStatement pstt = conn.prepareStatement(sql);
        // 参数已经强制要求是整型
        pstt.setInt(1, Integer.parseInt(req.getParameter("id")));
        ResultSet rs = pstt.executeQuery();
        while (rs.next()){
    

    0x02 框架使用不当造成 SQL 注入

    通常框架底层已经实现了对 SQL 注入的防御,但是如果在开发未能恰当的使用框架的情况下,依然会存在 SQL 注入的风险。

    1、MyBatis 框架

    MyBatis 的思想是将 SQL 语句编入配置文件中,避免 SQL 语句在代码中大量出现,方便对 SQL 语句的修改和配置。

    MyBatis 使用 parameterType 向 SQL 语句传参,在 SQL 引用传参的时候可以使用 #{} 和 ${} 两种方式,两种方式区别如下:

    ${}:SQL 拼接符号,直接将输入的语句拼接到 SQL 语句里,想避免 SQL 注入问题需要手动添加过滤

    #{}:占位符号,在对数据解析时会自动将输入的语句前后加上单引号从而避免 SQL 注入

    也就是说在 MyBatis 框架中,如果使用了 ${} 方法,同时又没有进行过滤就会产生 SQL 注入,而使用 #{} 方法时可以避免 SQL 注入。

    2、Hibernate 框架

    Hibernate 是现今主流的 Java 数据库持久化框架,采用 Hibernate 查询语句(HQL)注入。

    HQL 查询语句来自 Hibernate 引擎进行解析,因此产生的错误可能来自数据库,也有可能来自 Hibernate 引擎。

    HQL 和 SQL 的区别:

    image

    HQL 注入和 SQL 注入的成因都一样,使用拼接 HQL 语句的写法可能会导致 SQL 注入

    Query query = session.createQuery("from User where name='"+queryString+"'");
    

    但是受语法影响,HQL注入在漏洞利用上有一定的限制,比如不能利用联合查询、不能跨库查表、执行命令等。

    对于 Hibernate 的注入,这里只作为简单了解一下,平时代审的时候注意一下即可。

    参考文章:

    https://www.redhatzone.com/ask/article/1448.html

    https://blog.csdn.net/qq_36594628/article/details/119461996

    原文链接:

    https://www.teamssix.com/211117-091653.html

    相关文章

      网友评论

        本文标题:【代码审计】SQL 注入

        本文链接:https://www.haomeiwen.com/subject/lmrrtrtx.html