From 434b11695a9b8d50f557c5142d6f13682eefe104 Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 18 Mar 2013 21:28:35 +0800 Subject: [PATCH] improve WallFilter --- .../sql/visitor/SQLEvalVisitorUtils.java | 119 +++++++---- .../druid/sql/visitor/SchemaStatVisitor.java | 1 - .../com/alibaba/druid/wall/WallConfig.java | 9 + .../com/alibaba/druid/wall/WallContext.java | 13 +- .../com/alibaba/druid/wall/WallFilter.java | 63 ++++-- .../com/alibaba/druid/wall/WallProvider.java | 11 +- .../druid/wall/spi/MySqlWallProvider.java | 3 +- .../druid/wall/spi/OracleWallProvider.java | 3 +- .../druid/wall/spi/SQLServerWallProvider.java | 3 +- .../druid/wall/spi/WallVisitorUtils.java | 201 ++++-------------- .../wall/ConstantArithmeticCheckTest.java | 15 ++ .../druid/bvt/filter/wall/MySqlWallTest2.java | 19 +- 12 files changed, 227 insertions(+), 233 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/filter/wall/ConstantArithmeticCheckTest.java 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 7fe27f2d40..eabcb339e9 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -118,7 +118,9 @@ public class SQLEvalVisitorUtils { } public static boolean visit(SQLEvalVisitor visitor, SQLMethodInvokeExpr x) { - if ("concat".equalsIgnoreCase(x.getMethodName())) { + String methodName = x.getMethodName().toLowerCase(); + + if ("concat".equals(methodName)) { StringBuilder buf = new StringBuilder(); for (SQLExpr item : x.getParameters()) { @@ -132,9 +134,9 @@ public class SQLEvalVisitorUtils { } x.getAttributes().put(EVAL_VALUE, buf.toString()); - } else if ("now".equalsIgnoreCase(x.getMethodName())) { + } else if ("now".equals(methodName)) { x.getAttributes().put(EVAL_VALUE, new Date()); - } else if ("ascii".equalsIgnoreCase(x.getMethodName())) { + } else if ("ascii".equals(methodName)) { if (x.getParameters().size() == 0) { return false; } @@ -153,7 +155,7 @@ public class SQLEvalVisitorUtils { int ascii = strValue.charAt(0); x.getAttributes().put(EVAL_VALUE, ascii); - } else if ("instr".equalsIgnoreCase(x.getMethodName())) { + } else if ("instr".equals(methodName)) { if (x.getParameters().size() != 2) { return false; } @@ -175,7 +177,7 @@ public class SQLEvalVisitorUtils { int result = strValue0.indexOf(strValue1) + 1; x.putAttribute(EVAL_VALUE, result); - } else if ("left".equalsIgnoreCase(x.getMethodName())) { + } else if ("left".equals(methodName)) { if (x.getParameters().size() != 2) { return false; } @@ -197,7 +199,7 @@ public class SQLEvalVisitorUtils { String result = strValue.substring(0, intValue); x.putAttribute(EVAL_VALUE, result); - } else if ("right".equalsIgnoreCase(x.getMethodName())) { + } else if ("right".equals(methodName)) { if (x.getParameters().size() != 2) { return false; } @@ -219,7 +221,7 @@ public class SQLEvalVisitorUtils { String result = strValue.substring(strValue.length() - intValue, strValue.length()); x.putAttribute(EVAL_VALUE, result); - } else if ("reverse".equalsIgnoreCase(x.getMethodName())) { + } else if ("reverse".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -241,7 +243,7 @@ public class SQLEvalVisitorUtils { String result = buf.toString(); x.putAttribute(EVAL_VALUE, result); - } else if ("trim".equalsIgnoreCase(x.getMethodName())) { + } else if ("trim".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -258,7 +260,7 @@ public class SQLEvalVisitorUtils { String result = strValue.trim(); x.putAttribute(EVAL_VALUE, result); - } else if ("length".equalsIgnoreCase(x.getMethodName())) { + } else if ("length".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -276,7 +278,7 @@ public class SQLEvalVisitorUtils { int result = strValue.length(); x.putAttribute(EVAL_VALUE, result); - } else if ("ucase".equalsIgnoreCase(x.getMethodName()) || "upper".equalsIgnoreCase(x.getMethodName())) { + } else if ("ucase".equals(methodName) || "upper".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -294,7 +296,7 @@ public class SQLEvalVisitorUtils { String result = strValue.toUpperCase(); x.putAttribute(EVAL_VALUE, result); - } else if ("lcase".equalsIgnoreCase(x.getMethodName()) || "lower".equalsIgnoreCase(x.getMethodName())) { + } else if ("lcase".equals(methodName) || "lower".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -313,7 +315,7 @@ public class SQLEvalVisitorUtils { x.putAttribute(EVAL_VALUE, result); - } else if ("mod".equalsIgnoreCase(x.getMethodName())) { + } else if ("mod".equals(methodName)) { if (x.getParameters().size() != 2) { return false; } @@ -335,7 +337,7 @@ public class SQLEvalVisitorUtils { int result = intValue0 % intValue1; x.putAttribute(EVAL_VALUE, result); - } else if ("abs".equalsIgnoreCase(x.getMethodName())) { + } else if ("abs".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -358,7 +360,7 @@ public class SQLEvalVisitorUtils { } x.putAttribute(EVAL_VALUE, result); - } else if ("acos".equalsIgnoreCase(x.getMethodName())) { + } else if ("acos".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -379,7 +381,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("asin".equalsIgnoreCase(x.getMethodName())) { + } else if ("asin".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -400,7 +402,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("atan".equalsIgnoreCase(x.getMethodName())) { + } else if ("atan".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -421,7 +423,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("atan2".equalsIgnoreCase(x.getMethodName())) { + } else if ("atan2".equals(methodName)) { if (x.getParameters().size() != 2) { return false; } @@ -446,7 +448,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("ceil".equalsIgnoreCase(x.getMethodName()) || "ceiling".equalsIgnoreCase(x.getMethodName())) { + } else if ("ceil".equals(methodName) || "ceiling".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -467,7 +469,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("cos".equalsIgnoreCase(x.getMethodName())) { + } else if ("cos".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -488,7 +490,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("sin".equalsIgnoreCase(x.getMethodName())) { + } else if ("sin".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -509,7 +511,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("log".equalsIgnoreCase(x.getMethodName())) { + } else if ("log".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -530,7 +532,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("log10".equalsIgnoreCase(x.getMethodName())) { + } else if ("log10".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -551,7 +553,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("tan".equalsIgnoreCase(x.getMethodName())) { + } else if ("tan".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -572,7 +574,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("sqrt".equalsIgnoreCase(x.getMethodName())) { + } else if ("sqrt".equals(methodName)) { if (x.getParameters().size() != 1) { return false; } @@ -593,7 +595,7 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("power".equalsIgnoreCase(x.getMethodName())) { + } else if ("power".equals(methodName)) { if (x.getParameters().size() != 2) { return false; } @@ -618,10 +620,18 @@ public class SQLEvalVisitorUtils { } else { x.putAttribute(EVAL_VALUE, result); } - } else if ("pi".equalsIgnoreCase(x.getMethodName())) { + } else if ("pi".equals(methodName)) { x.putAttribute(EVAL_VALUE, Math.PI); - } else if ("rand".equalsIgnoreCase(x.getMethodName())) { + } else if ("rand".equals(methodName)) { x.putAttribute(EVAL_VALUE, Math.random()); + } else if ("chr".equals(methodName) && x.getParameters().size() == 1) { + SQLExpr first = x.getParameters().get(0); + Object firstResult = getValue(first); + if (firstResult instanceof Number) { + int intValue = ((Number) firstResult).intValue(); + char ch = (char) intValue; + x.putAttribute(EVAL_VALUE, Character.toString(ch)); + } } return false; } @@ -790,11 +800,11 @@ public class SQLEvalVisitorUtils { left.accept(visitor); right.accept(visitor); + final WallConditionContext wallConditionContext = WallVisitorUtils.getWallConditionContext(); if (x.getOperator() == SQLBinaryOperator.BooleanOr) { - final WallConditionContext wallContext = WallVisitorUtils.getWallConditionContext(); - if (wallContext != null) { + if (wallConditionContext != null) { if (left.getAttribute(EVAL_VALUE) == Boolean.TRUE || right.getAttribute(EVAL_VALUE) == Boolean.TRUE) { - wallContext.setPartAllowTrue(true); + wallConditionContext.setPartAlwayTrue(true); } } } @@ -807,52 +817,68 @@ public class SQLEvalVisitorUtils { return false; } + if (wallConditionContext != null) { + switch (x.getOperator()) { + case Add: + case Subtract: + case Multiply: + case Divide: + case Modulus: + wallConditionContext.setConstArithmetic(true); + break; + default: + break; + } + } + Object value = null; + Object leftValue = left.getAttribute(EVAL_VALUE); + Object rightValue = right.getAttributes().get(EVAL_VALUE); switch (x.getOperator()) { case Add: - value = add(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = add(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case Subtract: - value = sub(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = sub(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case Multiply: - value = multi(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = multi(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case Divide: - value = div(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = div(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case GreaterThan: - value = gt(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = gt(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case GreaterThanOrEqual: - value = gteq(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = gteq(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case LessThan: - value = lt(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = lt(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case LessThanOrEqual: - value = lteq(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = lteq(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case Is: case Equality: - value = eq(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = eq(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case IsNot: - value = !eq(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); + value = !eq(leftValue, rightValue); x.putAttribute(EVAL_VALUE, value); break; case RegExp: case RLike: { - String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String pattern = castToString(rightValue); String input = castToString(left.getAttributes().get(EVAL_VALUE)); boolean matchResult = Pattern.matches(pattern, input); x.putAttribute(EVAL_VALUE, matchResult); @@ -860,26 +886,31 @@ public class SQLEvalVisitorUtils { break; case NotRegExp: case NotRLike: { - String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String pattern = castToString(rightValue); String input = castToString(left.getAttributes().get(EVAL_VALUE)); boolean matchResult = !Pattern.matches(pattern, input); x.putAttribute(EVAL_VALUE, matchResult); } break; case Like: { - String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String pattern = castToString(rightValue); String input = castToString(left.getAttributes().get(EVAL_VALUE)); boolean matchResult = like(input, pattern); x.putAttribute(EVAL_VALUE, matchResult); } break; case NotLike: { - String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String pattern = castToString(rightValue); String input = castToString(left.getAttributes().get(EVAL_VALUE)); boolean matchResult = !like(input, pattern); x.putAttribute(EVAL_VALUE, matchResult); } break; + case Concat: { + String result = leftValue.toString() + rightValue.toString(); + x.putAttribute(EVAL_VALUE, result); + break; + } default: break; } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index 90629b21de..122e272561 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -58,7 +58,6 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; import com.alibaba.druid.sql.ast.statement.SQLTableElement; -import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.stat.TableStat; diff --git a/src/main/java/com/alibaba/druid/wall/WallConfig.java b/src/main/java/com/alibaba/druid/wall/WallConfig.java index e57aa285d9..8678766e8f 100644 --- a/src/main/java/com/alibaba/druid/wall/WallConfig.java +++ b/src/main/java/com/alibaba/druid/wall/WallConfig.java @@ -51,6 +51,7 @@ public class WallConfig implements WallConfigMBean { private boolean commentAllow = false; private boolean strictSyntaxCheck = true; + private boolean constArithmeticAllow = false; private boolean describeAllow = false; @@ -366,6 +367,14 @@ public class WallConfig implements WallConfigMBean { this.strictSyntaxCheck = strictSyntaxCheck; } + public boolean isConstArithmeticAllow() { + return constArithmeticAllow; + } + + public void setConstArithmeticAllow(boolean constArithmeticAllow) { + this.constArithmeticAllow = constArithmeticAllow; + } + public Set getDenyFunctions() { return denyFunctions; } diff --git a/src/main/java/com/alibaba/druid/wall/WallContext.java b/src/main/java/com/alibaba/druid/wall/WallContext.java index 5ba1942fea..59dd7ecc4d 100644 --- a/src/main/java/com/alibaba/druid/wall/WallContext.java +++ b/src/main/java/com/alibaba/druid/wall/WallContext.java @@ -20,11 +20,16 @@ public class WallContext { private final static ThreadLocal contextLocal = new ThreadLocal(); private WallSqlStat sqlState; + private final String dbType; - public static WallContext createIfNotExists() { + public WallContext(String dbType){ + this.dbType = dbType; + } + + public static WallContext createIfNotExists(String dbType) { WallContext context = contextLocal.get(); if (context == null) { - context = new WallContext(); + context = new WallContext(dbType); contextLocal.set(context); } return context; @@ -46,4 +51,8 @@ public class WallContext { this.sqlState = sqlState; } + public String getDbType() { + return dbType; + } + } diff --git a/src/main/java/com/alibaba/druid/wall/WallFilter.java b/src/main/java/com/alibaba/druid/wall/WallFilter.java index 826b565b06..50fe8a003a 100644 --- a/src/main/java/com/alibaba/druid/wall/WallFilter.java +++ b/src/main/java/com/alibaba/druid/wall/WallFilter.java @@ -159,7 +159,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public void statement_addBatch(FilterChain chain, StatementProxy statement, String sql) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); chain.statement_addBatch(statement, sql); @@ -171,7 +172,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareStatement(connection, sql); @@ -183,7 +185,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int autoGeneratedKeys) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys); @@ -196,7 +199,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency); @@ -209,7 +213,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency, @@ -222,7 +227,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int[] columnIndexes) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareStatement(connection, sql, columnIndexes); @@ -234,7 +240,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, String[] columnNames) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareStatement(connection, sql, columnNames); @@ -246,7 +253,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareCall(connection, sql); @@ -259,7 +267,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency); @@ -272,7 +281,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - WallContext.createIfNotExists(); + String dbType = connection.getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency, @@ -286,7 +296,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_execute(statement, sql); @@ -298,7 +309,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_execute(statement, sql, autoGeneratedKeys); @@ -310,7 +322,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[]) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_execute(statement, sql, columnIndexes); @@ -322,7 +335,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[]) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_execute(statement, sql, columnNames); @@ -334,7 +348,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_executeQuery(statement, sql); @@ -345,7 +360,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_executeUpdate(statement, sql); @@ -357,7 +373,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys); @@ -369,7 +386,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[]) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_executeUpdate(statement, sql, columnIndexes); @@ -381,7 +399,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { @Override public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[]) throws SQLException { - WallContext.createIfNotExists(); + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + WallContext.createIfNotExists(dbType); try { sql = check(sql); return chain.statement_executeUpdate(statement, sql, columnNames); @@ -465,15 +484,15 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean { public long getViolationCount() { return this.violationCount.get(); } - + public void resetViolationCount() { this.violationCount.set(0); } - + public void clearWhiteList() { this.provider.clearCache(); } - + public boolean checkValid(String sql) { return provider.checkValid(sql); } diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index d34846201f..4aa2dbc5b6 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -29,6 +29,7 @@ import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; import com.alibaba.druid.sql.visitor.ExportParameterVisitor; +import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.util.LRUCache; import com.alibaba.druid.wall.spi.WallVisitorUtils; import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation; @@ -54,9 +55,16 @@ public abstract class WallProvider { public final WallDenyStat commentDeniedStat = new WallDenyStat(); + protected String dbType = null; + public WallProvider(WallConfig config){ this.config = config; } + + public WallProvider(WallConfig config, String dbType){ + this.config = config; + this.dbType = dbType; + } public WallConfig getConfig() { return config; @@ -128,6 +136,7 @@ public abstract class WallProvider { public abstract ExportParameterVisitor createExportParameterVisitor(); public boolean checkValid(String sql) { + WallContext.createIfNotExists(dbType); WallCheckResult result = check(sql); return result.getViolations().isEmpty(); } @@ -262,7 +271,7 @@ public abstract class WallProvider { return result; } catch (ParserException e) { if (config.isStrictSyntaxCheck()) { - result.getViolations().add(new SyntaxErrorViolation(e, sql)); + result.getViolations().add(new SyntaxErrorViolation(e, sql)); } return result; } catch (Exception e) { diff --git a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallProvider.java b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallProvider.java index 8d29f6b93d..2f863bbedc 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallProvider.java @@ -19,6 +19,7 @@ import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlExportParameterVisitor; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.visitor.ExportParameterVisitor; +import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallProvider; import com.alibaba.druid.wall.WallVisitor; @@ -32,7 +33,7 @@ public class MySqlWallProvider extends WallProvider { } public MySqlWallProvider(WallConfig config){ - super(config); + super(config, JdbcConstants.MYSQL); } @Override diff --git a/src/main/java/com/alibaba/druid/wall/spi/OracleWallProvider.java b/src/main/java/com/alibaba/druid/wall/spi/OracleWallProvider.java index 78c9c3291a..a4ff337de3 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/OracleWallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/spi/OracleWallProvider.java @@ -19,6 +19,7 @@ import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleExportParameterVisitor; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.visitor.ExportParameterVisitor; +import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallProvider; import com.alibaba.druid.wall.WallVisitor; @@ -32,7 +33,7 @@ public class OracleWallProvider extends WallProvider { } public OracleWallProvider(WallConfig config){ - super(config); + super(config, JdbcConstants.ORACLE); } @Override diff --git a/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallProvider.java b/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallProvider.java index 8a10a6ade8..b636103280 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/spi/SQLServerWallProvider.java @@ -19,6 +19,7 @@ import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; import com.alibaba.druid.sql.dialect.sqlserver.visitor.MSSQLServerExportParameterVisitor; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.visitor.ExportParameterVisitor; +import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallProvider; import com.alibaba.druid.wall.WallVisitor; @@ -42,7 +43,7 @@ public class SQLServerWallProvider extends WallProvider { } public SQLServerWallProvider(WallConfig config){ - super(config); + super(config, JdbcConstants.SQL_SERVER); } @Override 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 386ad2cdbb..af982d4b5b 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -19,9 +19,9 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.math.BigDecimal; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Set; @@ -40,7 +40,6 @@ import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLNCharExpr; import com.alibaba.druid.sql.ast.expr.SQLNotExpr; -import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; @@ -59,17 +58,19 @@ import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBooleanExpr; import com.alibaba.druid.sql.visitor.ExportParameterVisitor; +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.JdbcUtils; import com.alibaba.druid.util.ServletPathMatcher; +import com.alibaba.druid.wall.WallContext; import com.alibaba.druid.wall.WallProvider; import com.alibaba.druid.wall.WallVisitor; import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation; public class WallVisitorUtils { - private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class); + private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class); public static void check(WallVisitor visitor, SQLInListExpr x) { @@ -121,17 +122,13 @@ public class WallVisitorUtils { return; } - if (!visitor.getConfig().isSelectWhereAlwayTrueCheck()) { - return; - } - SQLExpr where = x.getWhere(); if (where != null) { x.getWhere().setParent(x); checkCondition(visitor, x.getWhere()); - if (Boolean.TRUE == getConditionValue(visitor, where)) { + if (Boolean.TRUE == getConditionValue(visitor, where, visitor.getConfig().isSelectWhereAlwayTrueCheck())) { boolean isSimpleConstExpr = false; if (where instanceof SQLBinaryOpExpr) { SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) where; @@ -158,11 +155,7 @@ public class WallVisitorUtils { return; } - if (!visitor.getConfig().isSelectHavingAlwayTrueCheck()) { - return; - } - - if (Boolean.TRUE == getConditionValue(visitor, x)) { + if (Boolean.TRUE == getConditionValue(visitor, x, visitor.getConfig().isSelectHavingAlwayTrueCheck())) { addViolation(visitor, x); } } @@ -175,11 +168,9 @@ public class WallVisitorUtils { return; } - if (!visitor.getConfig().isDeleteWhereAlwayTrueCheck()) { - return; - } - - if (x.getWhere() == null || Boolean.TRUE == getConditionValue(visitor, x.getWhere())) { + if (x.getWhere() == null + || Boolean.TRUE == getConditionValue(visitor, x.getWhere(), + visitor.getConfig().isDeleteWhereAlwayTrueCheck())) { addViolation(visitor, x); return; } @@ -368,11 +359,9 @@ public class WallVisitorUtils { return; } - if (!visitor.getConfig().isUpdateWhereAlayTrueCheck()) { - return; - } - - if (x.getWhere() == null || Boolean.TRUE == getConditionValue(visitor, x.getWhere())) { + if (x.getWhere() == null + || Boolean.TRUE == getConditionValue(visitor, x.getWhere(), + visitor.getConfig().isUpdateWhereAlayTrueCheck())) { addViolation(visitor, x); return; } @@ -382,7 +371,6 @@ public class WallVisitorUtils { checkConditionForMultiTenant(visitor, x.getWhere(), x); } - @SuppressWarnings({ "unchecked", "rawtypes" }) public static Object getValue(SQLBinaryOpExpr x) { x.getLeft().setParent(x); x.getRight().setParent(x); @@ -434,7 +422,7 @@ public class WallVisitorUtils { if (Boolean.TRUE == result) { final WallConditionContext wallContext = WallVisitorUtils.getWallConditionContext(); if (wallContext != null) { - wallContext.setPartAllowTrue(true); + wallContext.setPartAlwayTrue(true); } return true; } @@ -458,11 +446,11 @@ public class WallVisitorUtils { if (Boolean.FALSE == leftResult || Boolean.FALSE == rightResult) { return false; } - + if (leftResult == Boolean.TRUE || rightResult == Boolean.TRUE) { final WallConditionContext current = wallConditionContextLocal.get(); if (current != null) { - current.setPartAllowTrue(true); + current.setPartAlwayTrue(true); } } @@ -471,162 +459,59 @@ public class WallVisitorUtils { } } - if (x.getOperator() == SQLBinaryOperator.Like) { - if (x.getRight() instanceof SQLCharExpr) { - String text = ((SQLCharExpr) x.getRight()).getText(); - - if (text.length() >= 0) { - for (char ch : text.toCharArray()) { - if (ch != '%') { - return null; - } - } - - return true; - } - - } + String dbType = null; + WallContext wallContext = WallContext.current(); + if (wallContext != null) { + dbType = wallContext.getDbType(); } - - if (leftResult == null || rightResult == null) { - return null; - } - - if (x.getOperator() == SQLBinaryOperator.Equality) { - if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { - return true; - } - - return leftResult.equals(rightResult); - } - - if (x.getOperator() == SQLBinaryOperator.NotEqual || x.getOperator() == SQLBinaryOperator.LessThanOrGreater) { - if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { - return false; - } - - if (leftResult == null || rightResult == null) { - return null; - } - - return !leftResult.equals(rightResult); - } - - if (x.getOperator() == SQLBinaryOperator.GreaterThan) { - if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { - return false; - } - - if (leftResult == null || rightResult == null) { - return null; - } - - if (leftResult instanceof Comparable) { - return (((Comparable) leftResult).compareTo(rightResult) > 0); - } - } - - if (x.getOperator() == SQLBinaryOperator.GreaterThanOrEqual) { - if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { - return false; - } - - if (leftResult == null || rightResult == null) { - return null; - } - - if (leftResult instanceof Comparable) { - return ((Comparable) leftResult).compareTo(rightResult) >= 0; - } - } - - if (x.getOperator() == SQLBinaryOperator.LessThan) { - if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { - return false; - } - - if (leftResult == null || rightResult == null) { - return null; - } - - if (leftResult instanceof Comparable) { - return (((Comparable) leftResult).compareTo(rightResult) < 0); - } - } - - if (x.getOperator() == SQLBinaryOperator.LessThanOrEqual) { - if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { - return false; - } - - if (leftResult == null || rightResult == null) { - return null; - } - - if (leftResult instanceof Comparable) { - return ((Comparable) leftResult).compareTo(rightResult) <= 0; - } - } - - if (x.getOperator() == SQLBinaryOperator.Concat) { - return leftResult.toString() + rightResult.toString(); - } - - if (x.getOperator() == SQLBinaryOperator.Add) { - if (leftResult == null || rightResult == null) { - return null; - } - - if (leftResult instanceof String || rightResult instanceof String) { - return leftResult.toString() + rightResult.toString(); - } - - if (leftResult instanceof Number || rightResult instanceof Number) { - return add((Number) leftResult, (Number) rightResult); - } - } - - return null; - } - - private static Number add(Number a, Number b) { - if (a instanceof BigDecimal) { - return ((BigDecimal) a).add(new BigDecimal(b.toString())); - } - - return a.longValue() + b.longValue(); + + return SQLEvalVisitorUtils.eval(dbType, x, Collections.emptyList(), false); } public static class WallConditionContext { private boolean partAllowTrue; + private boolean constArithmetic = false; public boolean isPartAllowTrue() { return partAllowTrue; } - public void setPartAllowTrue(boolean partAllowTrue) { + public void setPartAlwayTrue(boolean partAllowTrue) { this.partAllowTrue = partAllowTrue; } + + public boolean isConstArithmetic() { + return constArithmetic; + } + + public void setConstArithmetic(boolean constArithmetic) { + this.constArithmetic = constArithmetic; + } + } private static ThreadLocal wallConditionContextLocal = new ThreadLocal(); - + public static WallConditionContext getWallConditionContext() { return wallConditionContextLocal.get(); } - public static Object getConditionValue(WallVisitor visitor, SQLExpr x) { + public static Object getConditionValue(WallVisitor visitor, SQLExpr x, boolean alwayTrueCheck) { final WallConditionContext old = wallConditionContextLocal.get(); try { wallConditionContextLocal.set(new WallConditionContext()); final Object value = getValue(x); - + final WallConditionContext current = wallConditionContextLocal.get(); - if (current.isPartAllowTrue() && visitor.getConfig().isUpdateWhereAlayTrueCheck()) { + if (current.isPartAllowTrue() && alwayTrueCheck) { addViolation(visitor, x); } - + + if (current.isConstArithmetic() && !visitor.getConfig().isConstArithmeticAllow()) { + addViolation(visitor, x); + } + return value; } finally { wallConditionContextLocal.set(old); @@ -807,7 +692,7 @@ public class WallVisitorUtils { if (x instanceof SQLPropertyExpr) { return checkSchema(visitor, ((SQLPropertyExpr) x).getOwner()); } - + return true; } @@ -828,7 +713,7 @@ public class WallVisitorUtils { return false; } } - + return true; } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/ConstantArithmeticCheckTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/ConstantArithmeticCheckTest.java new file mode 100644 index 0000000000..738eee3df0 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/ConstantArithmeticCheckTest.java @@ -0,0 +1,15 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.wall.WallUtils; + +public class ConstantArithmeticCheckTest extends TestCase { + + public void test_true() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(// + "SELECT * from t where id = 3 - 1")); // + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest2.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest2.java index c4822f0968..d0bbfeefda 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest2.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest2.java @@ -19,6 +19,7 @@ import junit.framework.TestCase; import org.junit.Assert; +import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallUtils; /** @@ -30,13 +31,27 @@ import com.alibaba.druid.wall.WallUtils; */ public class MySqlWallTest2 extends TestCase { - public void test_stuff() throws Exception { + public void test_true() throws Exception { + WallConfig config = new WallConfig(); + config.setConstArithmeticAllow(true); Assert.assertTrue(WallUtils.isValidateMySql(// "select * from person_qingjia " + // "where isxiao=1 " + // "and ((starttime between 2013-01-15 and 2013-01-15)" + // " or (endtime between 2013-01- 15 and 2013-01-15)" + // ") " + // - "order by xiaojiatime desc")); + "order by xiaojiatime desc", config)); + } + + public void test_false() throws Exception { + WallConfig config = new WallConfig(); + config.setConstArithmeticAllow(true); + Assert.assertFalse(WallUtils.isValidateMySql(// + "select * from person_qingjia " + // + "where isxiao=1 " + // + "and ((starttime between 2013-01-15 and 2013-01-15)" + // + " or (endtime between 2013-01- 15 and 2013-01-15)" + // + ") " + // + "order by xiaojiatime desc", config)); } }