mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
modify sqlwall rules
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<WallConditionContext> wallConditionContextLocal = new ThreadLocal<WallConditionContext>();
|
||||
private static ThreadLocal<WallConditionContext> wallConditionContextLocal = new ThreadLocal<WallConditionContext>();
|
||||
private static ThreadLocal<WallSelectQueryContext> wallSelectQueryContextLocal = new ThreadLocal<WallSelectQueryContext>();
|
||||
private static ThreadLocal<WallTopStatementContext> wallTopStatementContextLocal = new ThreadLocal<WallTopStatementContext>();
|
||||
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user