之前写过一篇博客:《java:正则表达式检查SQL WHERE条件语句防止注入攻击和常量表达式》,当前时通过正则表达式来检查SQL语句中是否有危险关键字和常量表达式实现SQL语句的注入攻击检查。坦率的说,这个办法是有漏洞的,误判,漏判的概率很大,基于当前我的知识能力,也只能做到这样。
最近学习了jsqlparser,我知道我找到了更好的办法来解决SQL注入攻击检查问题。
jsqlparser是一个java的SQL语句解析器,在上一篇博客:《jsqlparser:基于抽象语法树(AST)遍历SQL语句的语法元素》介绍了如何通过jsqlparser来遍历SQL语句中所有的字段和表名引用。
其实它可以用来进行更复杂的工作,jsqlparser会将一条SQL语句的各种语法元素以抽象语法树(AST,abstract syntax tree)形式解析为很多不同类型对象,通过对AST的遍历就可以对SQL语句进行分析。采用这种方式做SQL注入攻击检查不会有误判,漏判的问题。

SqlInjectionAnalyzer

SqlInjectionAnalyzer SQL注入攻击分析器
jsqlparse提供了两种式遍历SQL语句解析对象,一种是基于TablesNamesFinder,TablesNamesFinder其实是实现jsqparser很多对象访问接口的一个基类
一种是基于CCJSqlParserDefaultVisitor接口。

/*** SQL注入攻击分析器* @author guyadong**/
public class SqlInjectionAnalyzer {private boolean injectCheckEnable = true;private final InjectionSyntaxObjectAnalyzer injectionChecker;private final InjectionAstNodeVisitor injectionVisitor;public SqlInjectionAnalyzer() {this.injectionChecker = new InjectionSyntaxObjectAnalyzer(); this.injectionVisitor = new InjectionAstNodeVisitor();}/*** 启用/关闭注入攻击检查,默认启动* @param enable* @return*/public SqlInjectionAnalyzer injectCheckEnable(boolean enable){injectCheckEnable = enable;return this;}/*** 对解析后的SQL对象执行注入攻击分析,有注入攻击的危险则抛出异常{@link InjectionAttackException}* @param sqlParserInfo* @throws InjectionAttackException */public SqlParserInfo injectAnalyse(SqlParserInfo sqlParserInfo) throws InjectionAttackException{if(null != sqlParserInfo && injectCheckEnable){/** SQL注入攻击检查 */sqlParserInfo.statement.accept(injectionChecker);sqlParserInfo.simpleNode.jjtAccept(injectionVisitor, null);             }return sqlParserInfo;}
}

InjectionSyntaxObjectAnalyzer

InjectionSyntaxObjectAnalyzer 为基于SQL语法对象的SQL注入攻击分析实现
TablesNamesFinder是jsqlparser提供的一个语法元素遍历对象,继承这个对象可以实现对需要的语法元素的访问,当遇到有注入攻击危险的表达式,语句时抛出InjectionAttackException异常,就是这个类做的工作


import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.util.TablesNamesFinder;/*** 基于SQL语法对象的SQL注入攻击分析实现* @author guyadong**/
public class InjectionSyntaxObjectAnalyzer  extends TablesNamesFinder{/** 危险函数名 */private static final String DANGROUS_FUNCTIONS = "(sleep|benchmark|extractvalue|updatexml|ST_LatFromGeoHash|ST_LongFromGeoHash|GTID_SUBSET|GTID_SUBTRACT|floor|ST_Pointfromgeohash"+ "|geometrycollection|multipoint|polygon|multipolygon|linestring|multilinestring)";private static ThreadLocal<Boolean> disableSubselect = new ThreadLocal<Boolean>(){@Overrideprotected Boolean initialValue() {return true;}};private ConstAnalyzer constAnalyzer = new ConstAnalyzer();public InjectionSyntaxObjectAnalyzer() {super();init(true);}@Overridepublic void visitBinaryExpression(BinaryExpression binaryExpression) {if(binaryExpression instanceof ComparisonOperator){if(isConst(binaryExpression.getLeftExpression()) && isConst(binaryExpression.getRightExpression())){/** 禁用恒等式 */throw new InjectionAttackException("DISABLE IDENTICAL EQUATION " + binaryExpression);}}super.visitBinaryExpression(binaryExpression);}@Overridepublic void visit(AndExpression andExpression) {super.visit(andExpression);checkConstExpress(andExpression.getLeftExpression());checkConstExpress(andExpression.getRightExpression());}@Overridepublic void visit(OrExpression orExpression) {super.visit(orExpression);checkConstExpress(orExpression.getLeftExpression());checkConstExpress(orExpression.getRightExpression());}@Overridepublic void visit(Function function) {if(function.getName().matches(DANGROUS_FUNCTIONS)){/** 禁用危险函数 */throw new InjectionAttackException("DANGROUS FUNCTION: "+function.getName());}super.visit(function);}@Overridepublic void visit(WithItem withItem) {try {/** 允许 WITH 语句中的子查询 */disableSubselect.set(false);super.visit(withItem);} finally {disableSubselect.set(true);}}@Overridepublic void visit(SubSelect subSelect) {if(disableSubselect.get()){// 禁用子查询throw new InjectionAttackException("DISABLE subselect " + subSelect);}}@Overridepublic void visit(Column tableColumn) {if(ParserSupport.isBoolean(tableColumn)){throw new InjectionAttackException("DISABLE CONST BOOL " + tableColumn);}super.visit(tableColumn);}@Overridepublic void visit(PlainSelect plainSelect) {if (plainSelect.getSelectItems() != null) {for (SelectItem item : plainSelect.getSelectItems()) {item.accept(this);}}if (plainSelect.getFromItem() != null) {plainSelect.getFromItem().accept(this);}if (plainSelect.getJoins() != null) {for (Join join : plainSelect.getJoins()) {join.getRightItem().accept(this);for(Expression e:join.getOnExpressions()){e.accept(this);}}}if (plainSelect.getWhere() != null) {plainSelect.getWhere().accept(this);checkConstExpress(plainSelect.getWhere());}if (plainSelect.getHaving() != null) {plainSelect.getHaving().accept(this);}if (plainSelect.getOracleHierarchical() != null) {plainSelect.getOracleHierarchical().accept(this);}if(plainSelect.getOrderByElements() != null){for( OrderByElement orderByElement : plainSelect.getOrderByElements()){orderByElement.getExpression().accept(this);}}if(plainSelect.getGroupBy() != null){for(Expression expression : plainSelect.getGroupBy().getGroupByExpressionList().getExpressions()){expression.accept(this);}}}private boolean isConst(Expression expression){return constAnalyzer.isConstExpression(expression);}private void checkConstExpress(Expression expression){if(constAnalyzer.isConstExpression(expression)){/** 禁用常量表达式 */throw new InjectionAttackException("DISABLE CONST EXPRESSION " + expression);}}
}

InjectionAstNodeVisitor

InjectionAstNodeVisitor 为基于抽象语法树(AST)的注入攻击分析实现
这部分代码很少,实现禁用用UNION语句

import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor;
import net.sf.jsqlparser.parser.SimpleNode;
import net.sf.jsqlparser.statement.select.UnionOp;/*** 基于抽象语法树(AST)的注入攻击分析实现* @author guyadong**/
public class InjectionAstNodeVisitor extends CCJSqlParserDefaultVisitor{public InjectionAstNodeVisitor() {}@Overridepublic Object visit(SimpleNode node, Object data) {Object value = node.jjtGetValue();if(value instanceof UnionOp){throw new InjectionAttackException("DISABLE UNION");}return super.visit(node, data);}
}

单元测试

InjectAttackCheckerTest SQL注入攻击检查测试

import static org.junit.Assert.*;import org.junit.BeforeClass;
import org.junit.Test;import gu.sql2java.parser.InjectionAttackException;
import gu.sql2java.parser.ParserSupport;
import gu.sql2java.parser.SqlInjectionAnalyzer;
import gu.sql2java.parser.ParserSupport.SqlParserInfo;
import net.sf.jsqlparser.JSQLParserException;import static gu.sql2java.SimpleLog.log;/*** SQL注入攻击检查测试* @author guyadong**/
public class InjectAttackCheckerTest {private static SqlInjectionAnalyzer analyser;@BeforeClasspublic static void setUpBeforeClass() throws Exception {analyser= new SqlInjectionAnalyzer();}private boolean injectAnalyse(String sql) throws JSQLParserException{SqlParserInfo sqlParserInfo = ParserSupport.parse0(sql, null);try {analyser.injectAnalyse(sqlParserInfo);return true;} catch (InjectionAttackException e) {log("{}",e.getMessage());//log(e);return false;}}@Testpublic void test() throws JSQLParserException {assertFalse(injectAnalyse("select * from dc_device where id in (select id from other)"));assertFalse(injectAnalyse("select * from dc_device where 2=2.0 or 2 != 4"));assertFalse(injectAnalyse("select * from dc_device where 1!=2.0"));assertFalse(injectAnalyse("select * from dc_device where id=floor(2.0)"));assertFalse(injectAnalyse("select * from dc_device where not true"));assertFalse(injectAnalyse("select * from dc_device where 1 or id > 0"));assertFalse(injectAnalyse("select * from dc_device where 'tom' or id > 0"));assertFalse(injectAnalyse("select * from dc_device where '-2.3' "));assertFalse(injectAnalyse("select * from dc_device where 2 "));assertFalse(injectAnalyse("select * from dc_device where (3+2) "));assertFalse(injectAnalyse("select * from dc_device where  -1 IS TRUE"));assertFalse(injectAnalyse("select * from dc_device where 'hello' is null "));assertFalse(injectAnalyse("select * from dc_device where '2022-10-31' and id > 0"));assertFalse(injectAnalyse("select * from dc_device where id > 0 or 1!=2.0 "));assertFalse(injectAnalyse("select * from dc_device where id > 0 or 1 in (1,3,4) "));assertFalse(injectAnalyse("select * from dc_device  UNION select name from other"));assertTrue(injectAnalyse("WITH SUB1 AS (SELECT user FROM t1) SELECT * FROM T2 WHERE id > 123 "));}}

完整代码参见码云仓库:
https://gitee.com/l0km/sql2java/tree/dev/sql2java-manager/src/main/java/gu/sql2java/parser

jsqlparser:实现基于SQL语法分析的SQL注入攻击检查相关推荐

  1. 基于pikachu漏洞平台的 --SQL注入攻击学习与总结

    SQL注入攻击 基础知识 常见注释符号 使用示例 pikachu 漏洞联系平台 -- SQL注入 SQL注入攻击流程 注入点类型 数字型注入(POST) 字符型注入(GET) 搜索型注入 XX型注入 ...

  2. 基于 WebGoat 平台的 SQL 注入攻击

    基于 WebGoat 平台的 SQL 注入攻击 扩展功能参考: https://blog.csdn.net/HZC0217/article/details/126790211 使用实例参考: http ...

  3. 基于Sqli-Labs靶场的SQL注入-第五关(重点讲双查询注入)

    目录 less-5:注入点为单引号的报错注入 什么是报错注入 常见的报错注入 什么是双查询注入 双查询中用到的语句以及函数 爆破数据库名字 双查询注入的报错原理 爆破数据库表名 爆破列名 爆破字段值 ...

  4. 一文搞懂SQL注入攻击

    SQL注入攻击 1. 前言 2. SQL注入简介 3. SQL注入步骤 4. 防范SQL注入 1. 前言 随着互联网的发展和普及,网络安全问题越来越突出,网络在为用户提供越来越多服务的同时,也要面对各 ...

  5. php安全编程—sql注入攻击

    原文:php安全编程-sql注入攻击 php安全编程--sql注入攻击 定义 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语 ...

  6. 【网络安全】SQL注入攻击思路手法总结(上)

    一.前言 本文为自己对SQL注入这个攻击手法的理解,跟大家一起分享SQL注入知识. 分上下篇,上篇为攻击手法概括,初稿不会写太多,后面会更新:下篇为防御篇,会把一些常见的,不常见的写进去. 二.概念 ...

  7. sql注入攻击与防御第二版读书笔记二——SQL盲注利用

    寻找并确认SQL盲注 强制产生通用错误 注入带副作用的查询 如 mssql waitfor delay '0:0:5' mysql sleep() 拆分与平衡 5 -> 7-2 常见SQL盲注场 ...

  8. python mysql倒序_day40:MySQL:python操作mysql:pymysql模块SQL注入攻击

    目录 part1:用python连接mysql 1.用python连接mysql的基本语法 创建连接conn→创建游标对象cursor→执行sql语句execute→获取数据fetchone→释放游标 ...

  9. sql参数化还是被注入了_SQL注入是什么?

    SQL注入(SQLi)是一种注入攻击,可以执行恶意SQL语句.它通过将任意SQL代码插入数据库查询,使攻击者能够完全控制Web应用程序后面的数据库服务器.攻击者可以使用SQL注入漏洞绕过应用程序安全措 ...

最新文章

  1. 功能强大的打包工具 NSIS,全部用脚本搞定 使用经验总结帖(持续更新中。。。)...
  2. SpringBoot中使用thymeleaf模板时select下拉框怎样查询数据库赋值
  3. Google C++单元测试框架(Gtest)系列教程之六——FAQ节选
  4. linux如何使用uboot的命令,Uboot常用命令使用
  5. 轴承新旧型号对照表_精密机床主轴轴承,高端轴承进口清关报关流程
  6. error C1853: “Debug\BigBuffer.pch”预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)...
  7. 代码简洁(注意事项)
  8. rk3399_secureboot在linux环境中操作说明
  9. 狂神说ElasitcSearch笔记(一)
  10. 实参与形参不兼容_python学习笔记------形参实参2
  11. 离散数学杜忠复版答案_离散数学(第二版)课后习题答案详解(完整版)
  12. Altera下载器使用说明 Intel(Altera)FPGA高速下载器线PL-USB2-BLASTER中文详细使用手册
  13. python下载itchat失败_Python itchat库的使用,pythonitchat,方法,小记
  14. XSS靶场练习手工注入(1)
  15. oracle wire protocol,WMB 8.0.0.2 在linux下面怎么配置连接ORACLE数据库
  16. 微信公众号菜单模板设置
  17. F - Sanae and Giant Robot
  18. If python is on the left-most side of the chain, that‘s the version you‘ve asked for.
  19. hp服务器怎么装win7系统,惠普280 Pro G4台式机intel 8代cpu安装win7步骤
  20. 数字图像处理总结(四)

热门文章

  1. STM32 MQTT协议 连接中国移动OneNet服务器 上传接收数据(三)STM32部分
  2. C#使用EPPlus.dll动态库在一般处理程序中实现将datatable导出到excel
  3. Ocean Optics USB2000光谱仪无法在Win10系统运行
  4. 使用css动画实现网易云音乐播放界面波浪动画效果
  5. 概率论知识点--上半学期
  6. 西门子200smart与v90伺服驱动器Profinet通讯。 sina-pos的运用
  7. 神兽保佑,代码无bug
  8. asp.net 自定义web控件
  9. 什么是接口测试及接口测试流程
  10. SpringAOP原理图解