• 源码分析 iBatis简单动态SQL处理($$)


      在iBatis中对于$param$的处理方法是怎么样的呢?下面将通过源码解读具体的处理逻辑

    public class SimpleDynamicSql implements Sql {
    
      private static final Probe PROBE = ProbeFactory.getProbe();
    
      // 分词字符
      private static final String ELEMENT_TOKEN = "$";
    
      private String sqlStatement;
    
      private SqlMapExecutorDelegate delegate;
    
      public SimpleDynamicSql(SqlMapExecutorDelegate delegate, String sqlStatement) {
        this.delegate = delegate;
        this.sqlStatement = sqlStatement;
      }
    // 获取sql
      public String getSql(StatementScope statementScope, Object parameterObject) {
        return processDynamicElements(sqlStatement, parameterObject);
      }
    
      public ParameterMap getParameterMap(StatementScope statementScope, Object parameterObject) {
        return statementScope.getParameterMap();
      }
    
      public ResultMap getResultMap(StatementScope statementScope, Object parameterObject) {
        return statementScope.getResultMap();
      }
    
      public void cleanup(StatementScope statementScope) {
      }
    // 如果sql不为null且存在$则认为是简单动态sql
      public static boolean isSimpleDynamicSql(String sql) {
        return sql != null && sql.indexOf(ELEMENT_TOKEN) > -1;
      }
    
      private String processDynamicElements(String sql, Object parameterObject) {
      // 新建一个分词工具
        StringTokenizer parser = new StringTokenizer(sql, ELEMENT_TOKEN, true);
        StringBuffer newSql = new StringBuffer();
    
        String token = null;
        String lastToken = null;
    	//如果sql中含有$
        while (parser.hasMoreTokens()) {
    	// 获取第一个分词对象
          token = parser.nextToken();
    		//如果最后一个分词对象等于$
          if (ELEMENT_TOKEN.equals(lastToken)) {
            if (ELEMENT_TOKEN.equals(token)) {
              newSql.append(ELEMENT_TOKEN);
              token = null;
            } else {
    // 如果lastToken=$且token不等于$则将token替换为token对应的属性值,默认为空字符串
              Object value = null;
              if (parameterObject != null) {
                if (delegate.getTypeHandlerFactory().hasTypeHandler(parameterObject.getClass())) {
                  value = parameterObject;
                } else {
                  value = PROBE.getObject(parameterObject, token);
                }
              }
              if (value != null) {
                newSql.append(String.valueOf(value));
              }
              //获取下一个分词,如果下一个分词不是$则抛出异常
              token = parser.nextToken();
              if (!ELEMENT_TOKEN.equals(token)) {
                throw new SqlMapException("Unterminated dynamic element in sql (" + sql + ").");
              }
              token = null;
            }
    		// 如果最后一个分词对象不等于$
          } else {
    	     //如果当前分词不是$在将当前分词追加在newSql中
            if (!ELEMENT_TOKEN.equals(token)) {
              newSql.append(token);
            }
    		// 如果当前分词等于$则不做任何处理
          }
    		//将当前分词赋值给最后一次分词
          lastToken = token;
        }
    
        return newSql.toString();
      }
    
    
    }

     例如:select * from $a$,param={a,tax_refund_info}的分词结果是:


    select * from

    $

    a

    $

    第一次循环:
      lastToken=null,
      token=select*from
     
      lastToken!=$

      newSql=select* from
     
     lastToken=select*from
     
    第二次循环
      lastToken=select * from
      token=$
     //doNothing
     lastToken=$
    第三次循环
      lastToken=$
      token=a;
     
      newSql=select * from tax_refund_info
     
     第三次循环
       lastToken=a;
       token=$
       //doNothing
       newSql=select * from  tax_refund_info
      
     我们可以发现这样的查询完全无法防止SQL注入攻击。

  • 相关阅读:
    git让线上代码强制覆盖本地的
    redis连接时报错:Could not connect to Redis at 127.0.0.1:6379: Connection refused
    Apache使用内置插件mod_php解析php的配置
    Apache2.4+PHP7.2配置站点访问变下载
    Linux下查看某一进程所占用内存的方法
    SNMP监控一些常用OID的总结
    kafka 生产消费原理详解
    HttpServletRequest接收参数的几种方法
    【转载】idea 2018注册码(激活码)永久性的
    SecureCRT & SecureFx 绿色破解版
  • 原文地址:https://www.cnblogs.com/wei-zw/p/8797774.html
Copyright © 2020-2023  润新知