diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java index c17eeaffe6..45642ca86d 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -85,6 +85,7 @@ import com.alibaba.druid.sql.visitor.functions.Unhex; import com.alibaba.druid.util.JdbcUtils; import com.alibaba.druid.wall.spi.WallVisitorUtils; import com.alibaba.druid.wall.spi.WallVisitorUtils.WallConditionContext; +import com.alibaba.druid.wall.spi.WallVisitorUtils.WallSelectQueryContext; public class SQLEvalVisitorUtils { @@ -739,6 +740,10 @@ public class SQLEvalVisitorUtils { if (x.getOperator() == SQLBinaryOperator.Like) { if (isAlwayTrueLikePattern(x.getRight())) { + final WallSelectQueryContext wallSelectQueryContext = WallVisitorUtils.getWallSelectQueryContext(); + if (wallSelectQueryContext != null) { + wallSelectQueryContext.setTrueLike(Boolean.TRUE); + } x.putAttribute(EVAL_VALUE, Boolean.TRUE); return false; } diff --git a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java index 0f666ff8b7..7a05993100 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java +++ b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java @@ -146,10 +146,16 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi @Override public boolean visit(SQLUpdateStatement x) { + WallVisitorUtils.initWallTopStatementContext(); WallVisitorUtils.checkUpdate(this, x); return true; } + @Override + public void endVisit(SQLUpdateStatement x) { + WallVisitorUtils.clearWallTopStatementContext(); + } + @Override public boolean visit(MySqlInsertStatement x) { return visit((SQLInsertStatement) x); @@ -170,9 +176,15 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi return false; } + WallVisitorUtils.initWallTopStatementContext(); return true; } + @Override + public void endVisit(SQLSelectStatement x) { + WallVisitorUtils.clearWallTopStatementContext(); + } + @Override public boolean visit(Limit x) { if (x.getRowCount() instanceof SQLNumericLiteralExpr) { diff --git a/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallVisitor.java b/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallVisitor.java index c122b229eb..c6e43a7a36 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallVisitor.java +++ b/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallVisitor.java @@ -98,12 +98,12 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements } public boolean visit(SQLIdentifierExpr x) { - String name = x.getName(); - name = WallVisitorUtils.form(name); - if (config.isVariantCheck() && config.getDenyVariants().contains(name)) { - getViolations().add(new IllegalSQLObjectViolation(ErrorCode.VARIANT_DENY, "variable not allow : " + name, - toSQL(x))); - } + // String name = x.getName(); + // name = WallVisitorUtils.form(name); + // if (config.isVariantCheck() && config.getDenyVariants().contains(name)) { + // getViolations().add(new IllegalSQLObjectViolation(ErrorCode.VARIANT_DENY, "variable not allow : " + name, + // toSQL(x))); + // } return true; } @@ -176,10 +176,16 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements this.toSQL(x))); return false; } + WallVisitorUtils.initWallTopStatementContext(); return true; } + @Override + public void endVisit(SQLSelectStatement x) { + WallVisitorUtils.clearWallTopStatementContext(); + } + @Override public boolean visit(SQLInsertStatement x) { WallVisitorUtils.checkInsert(this, x); @@ -194,11 +200,17 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements @Override public boolean visit(SQLUpdateStatement x) { + WallVisitorUtils.initWallTopStatementContext(); WallVisitorUtils.checkUpdate(this, x); return true; } + @Override + public void endVisit(SQLUpdateStatement x) { + WallVisitorUtils.clearWallTopStatementContext(); + } + public boolean visit(SQLVariantRefExpr x) { String varName = x.getName(); if (varName == null) { diff --git a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java index c8afde2973..4314b367bc 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -178,53 +178,64 @@ public class WallVisitorUtils { } public static void checkSelelct(WallVisitor visitor, SQLSelectQueryBlock x) { - for (SQLSelectItem item : x.getSelectList()) { - item.setParent(x); - } - if (x.getInto() != null) { - checkReadOnly(visitor, x.getInto()); - } + final WallSelectQueryContext old = wallSelectQueryContextLocal.get(); + try { + wallSelectQueryContextLocal.set(new WallSelectQueryContext()); - if (!visitor.getConfig().isSelectIntoAllow() && x.getInto() != null) { - addViolation(visitor, ErrorCode.SELECT_INTO_NOT_ALLOW, "select into not allow", x); - return; - } + for (SQLSelectItem item : x.getSelectList()) { + item.setParent(x); + } - if (x.getFrom() != null) { - x.getFrom().setParent(x); - } + if (x.getInto() != null) { + checkReadOnly(visitor, x.getInto()); + } - SQLExpr where = x.getWhere(); - if (where != null) { - where.setParent(x); - checkCondition(visitor, x.getWhere()); + if (!visitor.getConfig().isSelectIntoAllow() && x.getInto() != null) { + addViolation(visitor, ErrorCode.SELECT_INTO_NOT_ALLOW, "select into not allow", x); + return; + } - if (Boolean.TRUE == getConditionValue(visitor, where, visitor.getConfig().isSelectWhereAlwayTrueCheck())) { - boolean isSimpleConstExpr = false; - SQLExpr first = getFirst(where); + if (x.getFrom() != null) { + x.getFrom().setParent(x); + } - if (first == where) { - isSimpleConstExpr = true; - } else if (first instanceof SQLBinaryOpExpr) { - SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) first; + SQLExpr where = x.getWhere(); + if (where != null) { + where.setParent(x); + checkCondition(visitor, x.getWhere()); - if (binaryOpExpr.getOperator() == SQLBinaryOperator.Equality - || binaryOpExpr.getOperator() == SQLBinaryOperator.NotEqual) { - if (binaryOpExpr.getLeft() instanceof SQLIntegerExpr - && binaryOpExpr.getRight() instanceof SQLIntegerExpr) { - isSimpleConstExpr = true; + if (Boolean.TRUE == getConditionValue(visitor, where, visitor.getConfig().isSelectWhereAlwayTrueCheck())) { + boolean isSimpleConstExpr = false; + SQLExpr first = getFirst(where); + + if (first == where) { + isSimpleConstExpr = true; + } else if (first instanceof SQLBinaryOpExpr) { + SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) first; + + if (binaryOpExpr.getOperator() == SQLBinaryOperator.Equality + || binaryOpExpr.getOperator() == SQLBinaryOperator.NotEqual) { + if (binaryOpExpr.getLeft() instanceof SQLIntegerExpr + && binaryOpExpr.getRight() instanceof SQLIntegerExpr) { + isSimpleConstExpr = true; + } } } + + final WallSelectQueryContext current = wallSelectQueryContextLocal.get(); + if (!isSimpleConstExpr // 简单表达式 + && !(current != null && current.hasTrueLike()) // eg: like '%%' + ) { + addViolation(visitor, ErrorCode.ALWAY_TRUE, "select alway true condition not allow", x); + } } - if (!isSimpleConstExpr) { - addViolation(visitor, ErrorCode.ALWAY_TRUE, "select alway true condition not allow", x); - } } - + checkConditionForMultiTenant(visitor, x.getWhere(), x); + } finally { + wallSelectQueryContextLocal.set(old); } - checkConditionForMultiTenant(visitor, x.getWhere(), x); } public static void checkHaving(WallVisitor visitor, SQLExpr x) { @@ -743,6 +754,41 @@ public class WallVisitorUtils { } } + public static class WallSelectQueryContext { + + private boolean trueLike = false; + + public boolean hasTrueLike() { + return trueLike; + } + + public void setTrueLike(boolean trueLike) { + this.trueLike = trueLike; + } + } + + public static class WallTopStatementContext { + + private boolean fromSysTable = false; + private boolean fromSysSchema = false; + + public boolean fromSysTable() { + return fromSysTable; + } + + public void setFromSysTable(boolean fromSysTable) { + this.fromSysTable = fromSysTable; + } + + public boolean fromSysSchema() { + return fromSysSchema; + } + + public void setFromSysSchema(boolean fromSysSchema) { + this.fromSysSchema = fromSysSchema; + } + } + public static class WallConditionContext { private boolean partAlwayrue; @@ -781,14 +827,33 @@ public class WallVisitorUtils { public void setBitwise(boolean bitwise) { this.bitwise = bitwise; } + } - private static ThreadLocal wallConditionContextLocal = new ThreadLocal(); + private static ThreadLocal wallConditionContextLocal = new ThreadLocal(); + private static ThreadLocal wallSelectQueryContextLocal = new ThreadLocal(); + private static ThreadLocal wallTopStatementContextLocal = new ThreadLocal(); public static WallConditionContext getWallConditionContext() { return wallConditionContextLocal.get(); } + public static WallTopStatementContext getWallTopStatementContext() { + return wallTopStatementContextLocal.get(); + } + + public static void clearWallTopStatementContext() { + wallTopStatementContextLocal.set(null); + } + + public static void initWallTopStatementContext() { + wallTopStatementContextLocal.set(new WallTopStatementContext()); + } + + public static WallSelectQueryContext getWallSelectQueryContext() { + return wallSelectQueryContextLocal.get(); + } + public static Object getConditionValue(WallVisitor visitor, SQLExpr x, boolean alwayTrueCheck) { final WallConditionContext old = wallConditionContextLocal.get(); try { @@ -972,6 +1037,12 @@ public class WallVisitorUtils { } public static void checkFunction(WallVisitor visitor, SQLMethodInvokeExpr x) { + + final WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get(); + if (topStatementContext != null && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) { + return; + } + checkSchema(visitor, x.getOwner()); if (!visitor.getConfig().isFunctionCheck()) { @@ -1071,13 +1142,19 @@ public class WallVisitorUtils { } private static boolean checkSchema(WallVisitor visitor, SQLExpr x) { + final WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get(); + if (topStatementContext != null && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) { + return true; + } + if (x instanceof SQLName) { String owner = ((SQLName) x).getSimleName(); owner = WallVisitorUtils.form(owner); if (!visitor.getProvider().checkDenySchema(owner)) { - boolean topSelectStatement = isTopSelectStatement(x); + boolean topStatement = isTopSelectStatement(x) || isTopUpdateStatement(x); + boolean isWhereOrHaving = isWhereOrHaving(x); - if (!topSelectStatement) { + if (!topStatement && isWhereOrHaving) { SQLObject parent = x.getParent(); while (parent != null && !(parent instanceof SQLStatement)) { parent = parent.getParent(); @@ -1113,6 +1190,10 @@ public class WallVisitorUtils { if (!sameToTopSelectSchema) { addViolation(visitor, ErrorCode.SCHEMA_DENY, "deny schema : " + owner, x); } + } else { + if (topStatementContext != null) { + topStatementContext.setFromSysSchema(Boolean.TRUE); + } } return true; } @@ -1132,32 +1213,56 @@ public class WallVisitorUtils { } private static boolean isTopSelectStatement(SQLObject x) { + boolean topSelectStatement = false; SQLObject parent = x.getParent(); - if (parent instanceof SQLPropertyExpr) { - parent = parent.getParent(); - } - if (parent instanceof SQLExprTableSource) { - parent = parent.getParent(); - } - if (parent instanceof SQLSelectQueryBlock) { - parent = parent.getParent(); - } - if (parent instanceof SQLSelect) { - parent = parent.getParent(); - } - if (parent instanceof SQLSelectStatement || parent instanceof MySqlShowStatement) { - parent = parent.getParent(); - if (parent == null) { - topSelectStatement = true; + while (parent != null) { + + if (parent instanceof SQLSelectStatement || parent instanceof MySqlShowStatement) { + parent = parent.getParent(); + if (parent == null) { + topSelectStatement = true; + } + break; } + + if (parent instanceof SQLUnionQuery) { + SQLUnionQuery union = (SQLUnionQuery) parent; + if (union.getRight() == x) { + break; + } + } + + x = parent; + parent = x.getParent(); } + return topSelectStatement; } - public static boolean check(WallVisitor visitor, SQLExprTableSource x) { - SQLExpr expr = x.getExpr(); + private static boolean isTopUpdateStatement(SQLObject x) { + boolean topUpdateStatement = false; + while (x != null) { + if (x instanceof SQLUpdateStatement) { + x = x.getParent(); + if (x == null) { + topUpdateStatement = true; + } + break; + } + x = x.getParent(); + } + return topUpdateStatement; + } + + public static boolean check(WallVisitor visitor, SQLExprTableSource x) { + final WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get(); + if (topStatementContext != null && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) { + return true; + } + + SQLExpr expr = x.getExpr(); if (expr instanceof SQLPropertyExpr) { boolean checkResult = checkSchema(visitor, ((SQLPropertyExpr) expr).getOwner()); if (!checkResult) { @@ -1200,6 +1305,16 @@ public class WallVisitorUtils { } if (visitor.isDenyTable(tableName)) { + boolean topStatement = isTopSelectStatement(x) || isTopUpdateStatement(x); + boolean isWhereOrHaving = isWhereOrHaving(x); + + if (topStatement || !isWhereOrHaving) { + if (topStatementContext != null) { + topStatementContext.setFromSysTable(Boolean.TRUE); + } + return false; + } + boolean isTopNoneFrom = isTopSelectStatement(x); if (isTopNoneFrom) { return false;