modify sqlwall rules

This commit is contained in:
kiki
2013-06-03 14:19:09 +08:00
parent 83ff42fd79
commit 4bf86fb8e6
4 changed files with 205 additions and 61 deletions
@@ -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;