From ae814a7e8b31478d6f3aa9d4a8af5c0fb7411e1d Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Tue, 15 Apr 2025 15:03:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=BA=9F=E5=BC=83=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sqlInjection/InjectionAstNodeVisitor.java | 33 - .../InjectionSyntaxObjectAnalyzer.java | 172 ------ .../sqlInjection/SqlInjectionAnalyzer.java | 65 -- .../sqlInjection/parse/ConstAnalyzer.java | 569 ------------------ .../sqlInjection/parse/ParserSupport.java | 177 ------ .../parse/SqlSyntaxNormalizer.java | 37 -- 6 files changed, 1053 deletions(-) delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionAstNodeVisitor.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionSyntaxObjectAnalyzer.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/SqlInjectionAnalyzer.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ConstAnalyzer.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ParserSupport.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/SqlSyntaxNormalizer.java diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionAstNodeVisitor.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionAstNodeVisitor.java deleted file mode 100644 index 12444d9a9..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionAstNodeVisitor.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.jeecg.common.util.sqlInjection; - -import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor; -import net.sf.jsqlparser.parser.SimpleNode; -import net.sf.jsqlparser.statement.select.UnionOp; -import org.jeecg.common.exception.JeecgSqlInjectionException; - -/** - * 基于抽象语法树(AST)的注入攻击分析实现 - * - * @author guyadong - */ -public class InjectionAstNodeVisitor extends CCJSqlParserDefaultVisitor { - public InjectionAstNodeVisitor() { - } - - /** - * 处理禁止联合查询 - * - * @param node - * @param data - * @return - */ - @Override - public Object visit(SimpleNode node, Object data) { - Object value = node.jjtGetValue(); - if (value instanceof UnionOp) { - throw new JeecgSqlInjectionException("DISABLE UNION"); - } - return super.visit(node, data); - } -} - diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionSyntaxObjectAnalyzer.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionSyntaxObjectAnalyzer.java deleted file mode 100644 index b31f7c362..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/InjectionSyntaxObjectAnalyzer.java +++ /dev/null @@ -1,172 +0,0 @@ -package org.jeecg.common.util.sqlInjection; - - -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; -import org.jeecg.common.exception.JeecgSqlInjectionException; -import org.jeecg.common.util.sqlInjection.parse.ConstAnalyzer; -import org.jeecg.common.util.sqlInjection.parse.ParserSupport; - -/** - * 基于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 disableSubselect = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return true; - } - }; - private ConstAnalyzer constAnalyzer = new ConstAnalyzer(); - - public InjectionSyntaxObjectAnalyzer() { - super(); - init(true); - - } - - @Override - public void visitBinaryExpression(BinaryExpression binaryExpression) { - if (binaryExpression instanceof ComparisonOperator) { - if (isConst(binaryExpression.getLeftExpression()) && isConst(binaryExpression.getRightExpression())) { - /** 禁用恒等式 */ - throw new JeecgSqlInjectionException("DISABLE IDENTICAL EQUATION " + binaryExpression); - } - } - super.visitBinaryExpression(binaryExpression); - } - - @Override - public void visit(AndExpression andExpression) { - super.visit(andExpression); - checkConstExpress(andExpression.getLeftExpression()); - checkConstExpress(andExpression.getRightExpression()); - } - - @Override - public void visit(OrExpression orExpression) { - super.visit(orExpression); - checkConstExpress(orExpression.getLeftExpression()); - checkConstExpress(orExpression.getRightExpression()); - } - - @Override - public void visit(Function function) { - if (function.getName().matches(DANGROUS_FUNCTIONS)) { - /** 禁用危险函数 */ - throw new JeecgSqlInjectionException("DANGROUS FUNCTION: " + function.getName()); - } - super.visit(function); - } - - @Override - public void visit(WithItem withItem) { - try { - /** 允许 WITH 语句中的子查询 */ - disableSubselect.set(false); - super.visit(withItem); - } finally { - disableSubselect.set(true); - } - } - - @Override - public void visit(SubSelect subSelect) { - try { - /** 允许语句中的子查询 */ - disableSubselect.set(false); - super.visit(subSelect); - } finally { - disableSubselect.set(true); - } -// if (disableSubselect.get()) { -// // 禁用子查询 -// throw new JeecgSqlInjectionException("DISABLE subselect " + subSelect); -// } - } - - @Override - public void visit(Column tableColumn) { - if (ParserSupport.isBoolean(tableColumn)) { - throw new JeecgSqlInjectionException("DISABLE CONST BOOL " + tableColumn); - } - super.visit(tableColumn); - } - - @Override - public 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 JeecgSqlInjectionException("DISABLE CONST EXPRESSION " + expression); - } - } -} - - diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/SqlInjectionAnalyzer.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/SqlInjectionAnalyzer.java deleted file mode 100644 index 61f06a714..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/SqlInjectionAnalyzer.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.jeecg.common.util.sqlInjection; - -import org.jeecg.common.exception.JeecgSqlInjectionException; -import org.jeecg.common.util.sqlInjection.parse.ParserSupport; -; - -/** - * SQL注入攻击分析器 - * - * @author guyadong - * 参考: - * https://blog.csdn.net/10km/article/details/127767358 - * https://gitee.com/l0km/sql2java/tree/dev/sql2java-manager/src/main/java/gu/sql2java/parser - */ -public class SqlInjectionAnalyzer { - - //启用/关闭注入攻击检查 - private boolean injectCheckEnable = true; - //防止SQL注入攻击分析实现 - 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 JeecgSqlInjectionException} - * - * @param sqlParserInfo - * @throws JeecgSqlInjectionException - */ - public ParserSupport.SqlParserInfo injectAnalyse(ParserSupport.SqlParserInfo sqlParserInfo) throws JeecgSqlInjectionException { - if (null != sqlParserInfo && injectCheckEnable) { - /** SQL注入攻击检查 */ - sqlParserInfo.statement.accept(injectionChecker); - sqlParserInfo.simpleNode.jjtAccept(injectionVisitor, null); - } - return sqlParserInfo; - } - - /** - * sql校验 - */ - public static void checkSql(String sql,boolean check){ - SqlInjectionAnalyzer sqlInjectionAnalyzer = new SqlInjectionAnalyzer(); - sqlInjectionAnalyzer.injectCheckEnable(check); - ParserSupport.SqlParserInfo sqlParserInfo = ParserSupport.parse0(sql, null,null); - sqlInjectionAnalyzer.injectAnalyse(sqlParserInfo); - } -} - - diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ConstAnalyzer.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ConstAnalyzer.java deleted file mode 100644 index 9b7345c07..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ConstAnalyzer.java +++ /dev/null @@ -1,569 +0,0 @@ -package org.jeecg.common.util.sqlInjection.parse; - -import net.sf.jsqlparser.expression.*; -import net.sf.jsqlparser.expression.operators.arithmetic.Addition; -import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; -import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift; -import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr; -import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift; -import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor; -import net.sf.jsqlparser.expression.operators.arithmetic.Concat; -import net.sf.jsqlparser.expression.operators.arithmetic.Division; -import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision; -import net.sf.jsqlparser.expression.operators.arithmetic.Modulo; -import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication; -import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction; -import net.sf.jsqlparser.expression.operators.conditional.AndExpression; -import net.sf.jsqlparser.expression.operators.conditional.OrExpression; -import net.sf.jsqlparser.expression.operators.conditional.XorExpression; -import net.sf.jsqlparser.expression.operators.relational.Between; -import net.sf.jsqlparser.expression.operators.relational.EqualsTo; -import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.expression.operators.relational.FullTextSearch; -import net.sf.jsqlparser.expression.operators.relational.GeometryDistance; -import net.sf.jsqlparser.expression.operators.relational.GreaterThan; -import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals; -import net.sf.jsqlparser.expression.operators.relational.InExpression; -import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; -import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression; -import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; -import net.sf.jsqlparser.expression.operators.relational.ItemsListVisitor; -import net.sf.jsqlparser.expression.operators.relational.JsonOperator; -import net.sf.jsqlparser.expression.operators.relational.LikeExpression; -import net.sf.jsqlparser.expression.operators.relational.Matches; -import net.sf.jsqlparser.expression.operators.relational.MinorThan; -import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; -import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList; -import net.sf.jsqlparser.expression.operators.relational.NamedExpressionList; -import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; -import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator; -import net.sf.jsqlparser.expression.operators.relational.RegExpMySQLOperator; -import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.statement.select.AllColumns; -import net.sf.jsqlparser.statement.select.AllTableColumns; -import net.sf.jsqlparser.statement.select.OrderByElement; -import net.sf.jsqlparser.statement.select.SubSelect; - -/** - * 判断表达是否为常量的分析器 - * - * @author guyadong - */ -public class ConstAnalyzer implements ExpressionVisitor, ItemsListVisitor { - - private static ThreadLocal constFlag = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return true; - } - }; - - @Override - public void visit(NullValue value) { - } - - @Override - public void visit(Function function) { - constFlag.set(false); - } - - @Override - public void visit(SignedExpression expr) { - expr.getExpression().accept(this); - } - - @Override - public void visit(JdbcParameter parameter) { - constFlag.set(false); - } - - @Override - public void visit(JdbcNamedParameter parameter) { - constFlag.set(false); - } - - @Override - public void visit(DoubleValue value) { - - } - - @Override - public void visit(LongValue value) { - - } - - @Override - public void visit(DateValue value) { - - } - - @Override - public void visit(TimeValue value) { - - } - - @Override - public void visit(TimestampValue value) { - - } - - @Override - public void visit(Parenthesis parenthesis) { - parenthesis.getExpression().accept(this); - } - - @Override - public void visit(StringValue value) { - - } - - @Override - public void visit(Addition expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(Division expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(IntegerDivision expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(Multiplication expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(Subtraction expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(AndExpression expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(OrExpression expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(XorExpression expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(Between expr) { - expr.getLeftExpression().accept(this); - expr.getBetweenExpressionStart().accept(this); - expr.getBetweenExpressionEnd().accept(this); - } - - /** - * 用于处理 OverlapsCondition 类型的表达式 - * @param overlapsCondition - */ - @Override - public void visit(OverlapsCondition overlapsCondition) { - constFlag.set(false); - } - /** - * 用于处理 SafeCastExpression 类型的表达式。 - * @param safeCastExpression - */ - @Override - public void visit(SafeCastExpression safeCastExpression) { - constFlag.set(false); - } - - @Override - public void visit(EqualsTo expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(GreaterThan expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(GreaterThanEquals expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(InExpression expr) { - if (expr.getLeftExpression() != null) { - expr.getLeftExpression().accept(this); - } - } - - @Override - public void visit(IsNullExpression expr) { - expr.getLeftExpression().accept(this); - } - - @Override - public void visit(FullTextSearch expr) { - constFlag.set(false); - } - - @Override - public void visit(IsBooleanExpression expr) { - expr.getLeftExpression().accept(this); - } - - @Override - public void visit(LikeExpression expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(MinorThan expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(MinorThanEquals expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(NotEqualsTo expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(Column column) { - if (!ParserSupport.isBoolean(column)) { - constFlag.set(false); - } - } - - @Override - public void visit(SubSelect subSelect) { - constFlag.set(false); - } - - @Override - public void visit(CaseExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(WhenClause expr) { - constFlag.set(false); - } - - @Override - public void visit(ExistsExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(AnyComparisonExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(Concat expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(Matches expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(BitwiseAnd expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(BitwiseOr expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(BitwiseXor expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(CastExpression expr) { - expr.getLeftExpression().accept(this); - } - - @Override - public void visit(TryCastExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(Modulo expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(AnalyticExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(ExtractExpression expr) { - expr.getExpression().accept(this); - } - - @Override - public void visit(IntervalExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(OracleHierarchicalExpression expr) { - constFlag.set(false); - } - - @Override - public void visit(RegExpMatchOperator expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(ExpressionList expressionList) { - for (Expression expr : expressionList.getExpressions()) { - expr.accept(this); - } - } - - @Override - public void visit(NamedExpressionList namedExpressionList) { - for (Expression expr : namedExpressionList.getExpressions()) { - expr.accept(this); - } - } - - @Override - public void visit(MultiExpressionList multiExprList) { - for (ExpressionList list : multiExprList.getExpressionLists()) { - visit(list); - } - } - - @Override - public void visit(NotExpression notExpr) { - notExpr.getExpression().accept(this); - } - - @Override - public void visit(BitwiseRightShift expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(BitwiseLeftShift expr) { - visitBinaryExpression(expr); - } - - protected void visitBinaryExpression(BinaryExpression expr) { - expr.getLeftExpression().accept(this); - expr.getRightExpression().accept(this); - } - - @Override - public void visit(JsonExpression jsonExpr) { - jsonExpr.getExpression().accept(this); - } - - @Override - public void visit(JsonOperator expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(RegExpMySQLOperator expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(UserVariable var) { - constFlag.set(false); - } - - @Override - public void visit(NumericBind bind) { - constFlag.set(false); - } - - @Override - public void visit(KeepExpression expr) { - for (OrderByElement element : expr.getOrderByElements()) { - element.getExpression().accept(this); - } - } - - @Override - public void visit(MySQLGroupConcat groupConcat) { - constFlag.set(false); - } - - @Override - public void visit(ValueListExpression valueListExpression) { - for (Expression expr : valueListExpression.getExpressionList().getExpressions()) { - expr.accept(this); - } - } - - @Override - public void visit(AllColumns allColumns) { - - } - - @Override - public void visit(AllTableColumns allTableColumns) { - - } - - @Override - public void visit(AllValue allValue) { - - } - - @Override - public void visit(IsDistinctExpression isDistinctExpression) { - visitBinaryExpression(isDistinctExpression); - } - - @Override - public void visit(RowGetExpression rowGetExpression) { - rowGetExpression.getExpression().accept(this); - } - - @Override - public void visit(HexValue hexValue) { - - } - - @Override - public void visit(OracleHint hint) { - - } - - @Override - public void visit(TimeKeyExpression timeKeyExpression) { - - } - - @Override - public void visit(DateTimeLiteralExpression literal) { - } - - @Override - public void visit(NextValExpression nextVal) { - constFlag.set(false); - } - - @Override - public void visit(CollateExpression col) { - constFlag.set(false); - } - - @Override - public void visit(SimilarToExpression expr) { - visitBinaryExpression(expr); - } - - @Override - public void visit(ArrayExpression array) { - array.getObjExpression().accept(this); - if (array.getIndexExpression() != null) { - array.getIndexExpression().accept(this); - } - if (array.getStartIndexExpression() != null) { - array.getStartIndexExpression().accept(this); - } - if (array.getStopIndexExpression() != null) { - array.getStopIndexExpression().accept(this); - } - } - - @Override - public void visit(ArrayConstructor aThis) { - for (Expression expression : aThis.getExpressions()) { - expression.accept(this); - } - } - - @Override - public void visit(VariableAssignment var) { - constFlag.set(false); - } - - @Override - public void visit(XMLSerializeExpr expr) { - constFlag.set(false); - } - - @Override - public void visit(TimezoneExpression expr) { - expr.getLeftExpression().accept(this); - } - - @Override - public void visit(JsonAggregateFunction expression) { - Expression expr = expression.getExpression(); - if (expr != null) { - expr.accept(this); - } - - expr = expression.getFilterExpression(); - if (expr != null) { - expr.accept(this); - } - } - - @Override - public void visit(JsonFunction expression) { - for (JsonFunctionExpression expr : expression.getExpressions()) { - expr.getExpression().accept(this); - } - } - - @Override - public void visit(ConnectByRootOperator connectByRootOperator) { - constFlag.set(false); - } - - @Override - public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { - constFlag.set(false); - } - - @Override - public void visit(GeometryDistance geometryDistance) { - visitBinaryExpression(geometryDistance); - } - - @Override - public void visit(RowConstructor rowConstructor) { - constFlag.set(false); - } - - public boolean isConstExpression(Expression expression) { - if (null != expression) { - constFlag.set(true); - expression.accept(this); - return constFlag.get(); - } - return false; - } -} - diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ParserSupport.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ParserSupport.java deleted file mode 100644 index 880872679..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/ParserSupport.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.jeecg.common.util.sqlInjection.parse; - -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.*; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.select.PlainSelect; -import net.sf.jsqlparser.statement.select.Select; -import net.sf.jsqlparser.statement.select.SelectBody; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.lang.reflect.InvocationTargetException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.google.common.base.Throwables; -import org.jeecg.common.exception.JeecgBootException; -import org.jeecg.common.exception.JeecgSqlInjectionException; - -/** - * 解析sql支持 - */ -@Slf4j -public class ParserSupport { - /** - * 解析SELECT SQL语句,解析失败或非SELECT语句则抛出异常 - * - * @param sql - * @return - */ - public static Select parseSelect(String sql) { - Statement stmt; - try { - stmt = CCJSqlParserUtil.parse(checkNotNull(sql, "sql is null")); - } catch (JSQLParserException e) { - throw new JeecgBootException(e); - } - checkArgument(stmt instanceof Select, "%s is not SELECT statment", sql); - Select select = (Select) stmt; - SelectBody selectBody = select.getSelectBody(); - // 暂时只支持简单的SELECT xxxx FROM ....语句不支持复杂语句如WITH - checkArgument(selectBody instanceof PlainSelect, "ONLY SUPPORT plain select statement %s", sql); - return (Select) stmt; - } - - /** - * 解析SELECT SQL语句,解析失败或非SELECT语句则 - * - * @param sql - * @return - */ - public static Select parseSelectUnchecked(String sql) { - try { - return parseSelect(sql); - } catch (Exception e) { - return null; - } - } - - /** - * 实现SQL语句解析,解析成功则返回解析后的{@link Statement}, - * 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。 - * - * @param sql SQL语句 - * @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略 - * @param sqlSyntaxNormalizer SQL语句分析转换器,为{@code null}忽略 - * @throws JSQLParserException 输入的SQL语句有语法错误 - * @see #parse0(String, CCJSqlParserVisitor, SqlSyntaxNormalizer) - */ - public static Statement parse(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxNormalizer) throws JSQLParserException { - return parse0(sql, visitor, sqlSyntaxNormalizer).statement; - } - - /** - * 参照{@link CCJSqlParserUtil#parseAST(String)}和{@link CCJSqlParserUtil#parse(String)}实现SQL语句解析, - * 解析成功则返回解析后的{@link SqlParserInfo}对象, - * 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。 - * - * @param sql SQL语句 - * @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略 - * @param sqlSyntaxAnalyzer SQL语句分析转换器,为{@code null}忽略 - * @throws JSQLParserException 输入的SQL语句有语法错误 - * @see net.sf.jsqlparser.parser.Node#jjtAccept(SimpleNodeVisitor, Object) - */ - public static SqlParserInfo parse0(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxAnalyzer) throws JeecgSqlInjectionException { - - //检查是否非select开头,暂不支持 - if(!sql.toLowerCase().trim().startsWith("select ")) { - log.warn("传入sql 非select开头,不支持非select开头的语句解析!"); - return null; - } - - //检查是否存储过程,暂不支持 - if(sql.toLowerCase().trim().startsWith("call ")){ - log.warn("传入call 开头存储过程,不支持存储过程解析!"); - return null; - } - - //检查特殊语义的特殊字符,目前检查冒号、$、#三种特殊语义字符 - String specialCharacters = "[:$#]"; - Pattern pattern = Pattern.compile(specialCharacters); - Matcher matcher = pattern.matcher(sql); - if (matcher.find()) { - sql = sql.replaceAll("[:$#]", "@"); - } - - checkArgument(null != sql, "sql is null"); - boolean allowComplexParsing = CCJSqlParserUtil.getNestingDepth(sql) <= CCJSqlParserUtil.ALLOWED_NESTING_DEPTH; - - CCJSqlParser parser = CCJSqlParserUtil.newParser(sql).withAllowComplexParsing(allowComplexParsing); - Statement stmt; - try { - stmt = parser.Statement(); - } catch (Exception ex) { - log.error("请注意,SQL语法可能存在问题---> {}", ex.getMessage()); - throw new JeecgSqlInjectionException("请注意,SQL语法可能存在问题:"+sql); - } - if (null != visitor) { - parser.getASTRoot().jjtAccept(visitor, null); - } - if (null != sqlSyntaxAnalyzer) { - stmt.accept(sqlSyntaxAnalyzer.resetChanged()); - } - return new SqlParserInfo(stmt.toString(), stmt, (SimpleNode) parser.getASTRoot()); - } - - /** - * 调用{@link CCJSqlParser}解析SQL语句部件返回解析生成的对象,如{@code 'ORDER BY id DESC'} - * - * @param - * @param input - * @param method 指定调用的{@link CCJSqlParser}解析方法 - * @param targetType 返回的解析对象类型 - * @return - * @since 3.18.3 - */ - public static T parseComponent(String input, String method, Class targetType) { - try { - CCJSqlParser parser = new CCJSqlParser(new StringProvider(input)); - try { - return checkNotNull(targetType, "targetType is null").cast(parser.getClass().getMethod(method).invoke(parser)); - } catch (InvocationTargetException e) { - Throwables.throwIfUnchecked(e.getTargetException()); - throw new RuntimeException(e.getTargetException()); - } - } catch (IllegalAccessException | NoSuchMethodException | SecurityException e) { - Throwables.throwIfUnchecked(e); - throw new RuntimeException(e); - } - } - - /** - * 如果{@link Column}没有定义table,且字段名为true/false(不区分大小写)则视为布尔常量 - * - * @param column - */ - public static boolean isBoolean(Column column) { - return null != column && null == column.getTable() && - Pattern.compile("(true|false)", Pattern.CASE_INSENSITIVE).matcher(column.getColumnName()).matches(); - } - - public static class SqlParserInfo { - public String nativeSql; - public Statement statement; - public SimpleNode simpleNode; - - SqlParserInfo(String nativeSql, Statement statement, SimpleNode simpleNode) { - this.nativeSql = nativeSql; - this.statement = statement; - this.simpleNode = simpleNode; - } - } -} - diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/SqlSyntaxNormalizer.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/SqlSyntaxNormalizer.java deleted file mode 100644 index 844478197..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlInjection/parse/SqlSyntaxNormalizer.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.jeecg.common.util.sqlInjection.parse; - -import net.sf.jsqlparser.util.TablesNamesFinder; - -/** - * SQL语句分析转换器基类
- * 基于SQL语法对象实现对SQL的修改 - * (暂时用不到) - * - * @author guyadong - * @since 3.17.0 - */ -public class SqlSyntaxNormalizer extends TablesNamesFinder { - protected static final ThreadLocal changed = new ThreadLocal<>(); - - public SqlSyntaxNormalizer() { - super(); - init(true); - - } - - /** - * 语句改变返回{@code true},否则返回{@code false} - */ - public boolean changed() { - return Boolean.TRUE.equals(changed.get()); - } - - /** - * 复位线程局部变量{@link #changed}状态 - */ - public SqlSyntaxNormalizer resetChanged() { - changed.remove(); - return this; - } -} -