diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectStatement.java index 1a559d1b77..2541d9acdf 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectStatement.java @@ -29,8 +29,7 @@ public class SQLSelectStatement extends SQLStatementImpl { } public SQLSelectStatement(SQLSelect select){ - - this.select = select; + this.setSelect(select); } public SQLSelect getSelect() { @@ -38,6 +37,9 @@ public class SQLSelectStatement extends SQLStatementImpl { } public void setSelect(SQLSelect select) { + if (select != null) { + select.setParent(this); + } this.select = select; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowGrantsStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowGrantsStatement.java index 30754e44c1..4dc8f3cae1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowGrantsStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowGrantsStatement.java @@ -36,6 +36,9 @@ public class MySqlShowGrantsStatement extends MySqlStatementImpl implements MySq } public void setUser(SQLExpr user) { + if (user != null) { + user.setParent(this); + } this.user = user; } diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java index dd650e20f6..7eb98a517a 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java @@ -210,24 +210,30 @@ public final class DruidStatManagerFacade { } else if (valueB == null) { newMap.put(key, valueA); } else if ("blackList".equals(key)) { - Set newSet = new HashSet(); + Map> newSet = new HashMap>(); - Collection collectionA = (Collection) valueA; - for (String blackItem : collectionA) { + Collection> collectionA = (Collection>) valueA; + for (Map blackItem : collectionA) { if (newSet.size() >= 1000) { break; } - newSet.add(blackItem); + + String sql = (String) blackItem.get("sql"); + Map oldItem = newSet.get(sql); + newSet.put(sql, mergWallStat(oldItem, blackItem)); } - Collection collectionB = (Collection) valueB; - for (String blackItem : collectionB) { + Collection> collectionB = (Collection>) valueB; + for (Map blackItem : collectionB) { if (newSet.size() >= 1000) { break; } - newSet.add(blackItem); + + String sql = (String) blackItem.get("sql"); + Map oldItem = newSet.get(sql); + newSet.put(sql, mergWallStat(oldItem, blackItem)); } - newMap.put(key, newSet); + newMap.put(key, newSet.values()); } else { if (valueA instanceof Map && valueB instanceof Map) { Object newValue = mergWallStat((Map)valueA, (Map)valueB); @@ -240,7 +246,7 @@ public final class DruidStatManagerFacade { } else if (valueA instanceof List && valueB instanceof List) { List> mergedList = mergeNamedList((List) valueA, (List) valueB); newMap.put(key, mergedList); - } else if (valueA instanceof String && valueB instanceof String && valueA.equals(valueB) && "name".equals(key)) { + } else if (valueA instanceof String && valueB instanceof String && valueA.equals(valueB)) { newMap.put(key, valueA); } else { Object sum = SQLEvalVisitorUtils.add(valueA, valueB); diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index 6e23464b7b..1405ae8cdf 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -155,6 +155,7 @@ public abstract class WallProvider { WallSqlStat wallStat = whiteList.get(sql); if (wallStat == null) { wallStat = new WallSqlStat(tableStats, functionStats, syntaxError); + wallStat.incrementAndGetExecuteCount(); whiteList.put(sql, wallStat); } @@ -176,6 +177,7 @@ public abstract class WallProvider { WallSqlStat wallStat = blackList.get(sql); if (wallStat == null) { wallStat = new WallSqlStat(tableStats, functionStats, violations, syntaxError); + wallStat.incrementAndGetExecuteCount(); blackList.put(sql, wallStat); } @@ -212,6 +214,33 @@ public abstract class WallProvider { return Collections. unmodifiableSet(hashSet); } + + public List> getBlackListStat() { + List> map = new ArrayList>(); + lock.readLock().lock(); + try { + if (blackList != null) { + for (Map.Entry entry : this.blackList.entrySet()) { + WallSqlStat sqlStat = entry.getValue(); + + Map sqlStatMap = new LinkedHashMap(); + sqlStatMap.put("sql", entry.getKey()); + sqlStatMap.put("executeCount", sqlStat.getExecuteCount()); + + List violations = sqlStat.getViolations(); + if (violations.size() > 0) { + sqlStatMap.put("violationMessage", violations.get(0).getMessage()); + } + + map.add(sqlStatMap); + } + } + } finally { + lock.readLock().unlock(); + } + + return map; + } public void clearCache() { clearWhiteList(); @@ -312,6 +341,10 @@ public abstract class WallProvider { if (schemaName == null) { return true; } + + if (!this.config.isSchemaCheck()) { + return true; + } schemaName = schemaName.toLowerCase(); if (getConfig().getDenySchemas().contains(schemaName)) { @@ -638,7 +671,7 @@ public abstract class WallProvider { info.put("functions", functions); } // info.put("whiteList", this.getWhiteList()); - info.put("blackList", this.getBlackList()); + info.put("blackList", this.getBlackListStat()); return info; } } 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 7c4c051c73..fef2c3c84c 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java +++ b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java @@ -191,7 +191,10 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi } if (!checkVar(x.getParent(), x.getName())) { - violations.add(new IllegalSQLObjectViolation("variable not allow : " + x.getName(), toSQL(x))); + boolean isTop = WallVisitorUtils.isTopNoneFromSelect(x); + if (!isTop) { + violations.add(new IllegalSQLObjectViolation("variable not allow : " + x.getName(), toSQL(x))); + } } return false; } @@ -236,7 +239,10 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi } if (varName.startsWith("@@") && !checkVar(x.getParent(), x.getName())) { - violations.add(new IllegalSQLObjectViolation("variable not allow : " + x.getName(), toSQL(x))); + boolean isTop = WallVisitorUtils.isTopNoneFromSelect(x); + if (!isTop) { + violations.add(new IllegalSQLObjectViolation("variable not allow : " + x.getName(), toSQL(x))); + } } return false; @@ -344,12 +350,12 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi public boolean visit(SQLSetStatement x) { return false; } - + @Override public boolean visit(MySqlReplaceStatement x) { return true; } - + @Override public boolean visit(SQLCallStatement x) { return false; 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 9128dc8cb5..9bcb7d8511 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -74,6 +74,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetCharSetStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetNamesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowGrantsStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; @@ -818,9 +819,86 @@ public class WallVisitorUtils { } if (!visitor.getProvider().checkDenyFunction(methodName)) { + boolean isTopNoneFrom = isTopNoneFromSelect(x); + if (isTopNoneFrom) { + return; + } + + boolean isShow = x.getParent() instanceof MySqlShowGrantsStatement; + if (isShow) { + return; + } + + if ("CONNECTION_ID".equalsIgnoreCase(methodName)) { + SQLSelectQueryBlock queryBlock = getQueryBlock(x); + if (queryBlock != null) { + if (queryBlock.getFrom() instanceof SQLExprTableSource) { + SQLExpr expr = ((SQLExprTableSource) queryBlock.getFrom()).getExpr(); + if ("information_schema.processlist".equalsIgnoreCase(expr.toString())) { + return; + } + } + } + } + addViolation(visitor, "deny function : " + methodName, x); } + } + public static SQLSelectQueryBlock getQueryBlock(SQLObject x) { + if (x == null) { + return null; + } + + if (x instanceof SQLSelectQueryBlock) { + return (SQLSelectQueryBlock) x; + } + + SQLObject parent = x.getParent(); + + if (parent instanceof SQLExpr) { + return getQueryBlock(parent); + } + + if (parent instanceof SQLSelectItem) { + return getQueryBlock(parent); + } + + if (parent instanceof SQLSelectQueryBlock) { + return (SQLSelectQueryBlock) parent; + } + + return null; + } + + public static boolean isTopNoneFromSelect(SQLExpr x) { + if (!(x.getParent() instanceof SQLSelectItem)) { + return false; + } + SQLSelectItem item = (SQLSelectItem) x.getParent(); + + if (!(item.getParent() instanceof SQLSelectQueryBlock)) { + return false; + } + + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) item.getParent(); + if (!queryBlockFromIsNull(queryBlock)) { + return false; + } + + if (!(queryBlock.getParent() instanceof SQLSelect)) { + return false; + } + + SQLSelect select = (SQLSelect) queryBlock.getParent(); + + if (!(select.getParent() instanceof SQLSelectStatement)) { + return false; + } + + SQLSelectStatement stmt = (SQLSelectStatement) select.getParent(); + + return stmt.getParent() == null; } private static boolean checkSchema(WallVisitor visitor, SQLExpr x) { @@ -829,12 +907,12 @@ public class WallVisitorUtils { owner = WallVisitorUtils.form(owner); if (!visitor.getProvider().checkDenySchema(owner)) { addViolation(visitor, "deny schema : " + owner, x); - return false; + return true; } if (visitor.getConfig().isDenyObjects(owner)) { addViolation(visitor, "deny object : " + owner, x); - return false; + return true; } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallPermitTableTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallPermitTableTest.java index bbb2b6e797..90ff591693 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallPermitTableTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallPermitTableTest.java @@ -25,14 +25,14 @@ import com.alibaba.druid.wall.WallUtils; public class MySqlWallPermitTableTest extends TestCase { public void test_default() throws Exception { - Assert.assertFalse(WallUtils.isValidateMySql("select benchmark( 500000, sha1( 'test' ) )")); + Assert.assertFalse(WallUtils.isValidateMySql("select benchmark( 500000, sha1( 'test' ) ) FROM X")); } public void test_allow() throws Exception { WallConfig config = new WallConfig(); config.setTableCheck(false); - Assert.assertTrue(WallUtils.isValidateMySql("select benchmark( 500000, sha1( 'test' ) )", config)); + Assert.assertTrue(WallUtils.isValidateMySql("select benchmark( 500000, sha1( 'test' ) ) FROM X", config)); } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest.java index b4b0b28135..04ba6f5779 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest.java @@ -30,7 +30,7 @@ public class MySqlWallTest extends TestCase { Assert.assertFalse(WallUtils.isValidateMySql("select hex(load_file(0x633A2F77696E646F77732F7265706169722F73616D))")); Assert.assertTrue(WallUtils.isValidateMySql("select 'hex(load_file(0x633A2F77696E646F77732F7265706169722F73616D))'")); - Assert.assertFalse(WallUtils.isValidateMySql("select 15,version()")); + Assert.assertFalse(WallUtils.isValidateMySql("select 15,version() FROM X")); Assert.assertTrue(WallUtils.isValidateMySql("select 15,'version'")); Assert.assertFalse(WallUtils.isValidateMySql("select 1 from information_schema.columns")); diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitFunctionTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitFunctionTest.java index a510486b68..809958d103 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitFunctionTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitFunctionTest.java @@ -30,13 +30,13 @@ import com.alibaba.druid.wall.WallUtils; public class OracleWallPermitFunctionTest extends TestCase { public void test_permitTable() throws Exception { - Assert.assertFalse(WallUtils.isValidateOracle("select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from dual")); + Assert.assertFalse(WallUtils.isValidateOracle("select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from X")); } public void test_permitTable_allow() throws Exception { WallConfig config = new WallConfig(); config.setFunctionCheck(false); - Assert.assertTrue(WallUtils.isValidateOracle("select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from dual", config)); + Assert.assertTrue(WallUtils.isValidateOracle("select SYS_CONTEXT ('USERENV', 'CURRENT_USER') from X", config)); } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/SQLServerWallPermitFunctionTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/SQLServerWallPermitFunctionTest.java index ce19941227..1799c2071f 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/SQLServerWallPermitFunctionTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/SQLServerWallPermitFunctionTest.java @@ -52,7 +52,7 @@ public class SQLServerWallPermitFunctionTest extends TestCase { } public void test01() throws Exception { - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT user_name();")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT user_name() FROM X;")); } public final void test_sp_addsrvrolemenber() throws Exception { @@ -72,12 +72,12 @@ public class SQLServerWallPermitFunctionTest extends TestCase { } public final void test_db_name() throws Exception { - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT DB_NAME()")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT DB_NAME(0); ")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT DB_NAME() FROM X")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT DB_NAME(0) FROM X; ")); } public final void test_host_name() throws Exception { - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT HOST_NAME()")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT HOST_NAME() FROM X")); } /** @@ -85,16 +85,16 @@ public class SQLServerWallPermitFunctionTest extends TestCase { * @throws Exception */ public void test_is_srvrolemember() throws Exception { - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘sysadmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘dbcreator’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘bulkadmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘diskadmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘processadmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘serveradmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘setupadmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘securityadmin’);")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘sysadmin’); ")); - Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘sysadmin’, ‘sa’); ")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘sysadmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘dbcreator’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘bulkadmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘diskadmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘processadmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘serveradmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘setupadmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘securityadmin’) FROM X;")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘sysadmin’) FROM X; ")); + Assert.assertFalse(WallUtils.isValidateSqlServer("SELECT is_srvrolemember(‘sysadmin’, ‘sa’) FROM X; ")); } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_statMap.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_statMap.java index f5b4c271e1..c1429bd190 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_statMap.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_statMap.java @@ -55,11 +55,11 @@ public class WallStatTest_statMap extends TestCase { System.out.println(JSONUtils.toJSONString(statMapMerged)); Assert.assertEquals(2L, statMapMerged.get("checkCount")); - Assert.assertEquals(2, ((Collection) statMapMerged.get("blackList")).size()); + Assert.assertEquals(2, ((Collection>) statMapMerged.get("blackList")).size()); statMapMerged = DruidStatManagerFacade.mergWallStat(statMapMerged, statMapC); System.out.println(JSONUtils.toJSONString(statMapMerged)); - Assert.assertEquals(2, ((Collection) statMapMerged.get("blackList")).size()); + Assert.assertEquals(2, ((Collection>) statMapMerged.get("blackList")).size()); } }