diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java b/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java index cc8dc0cd97..3e5a7481c5 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java @@ -19,11 +19,13 @@ import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; 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.MySqlOutFileExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectGroupBy; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter; @@ -90,27 +92,33 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi public List getViolations() { return violations; } - + public boolean visit(SQLPropertyExpr x) { WallVisitorUtils.check(this, x); return true; } public boolean visit(SQLBinaryOpExpr x) { - WallVisitorUtils.check(this, x); - return true; } @Override public boolean visit(SQLSelectQueryBlock x) { - if (x.getWhere() != null) { - x.getWhere().setParent(x); - } + WallVisitorUtils.checkCondition(this, x.getWhere()); return true; } + public boolean visit(SQLSelectGroupByClause x) { + WallVisitorUtils.checkCondition(this, x.getHaving()); + return true; + } + + public boolean visit(MySqlSelectGroupBy x) { + WallVisitorUtils.checkCondition(this, x.getHaving()); + return true; + } + @Override public boolean visit(MySqlSelectQueryBlock x) { return visit((SQLSelectQueryBlock) x); diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java b/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java index 794ce09a02..c043cc8960 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java @@ -20,11 +20,14 @@ import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVIsitorAdapter; @@ -108,8 +111,6 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi // executeQuery public boolean visit(SQLBinaryOpExpr x) { - WallVisitorUtils.check(this, x); - return true; } @@ -140,6 +141,23 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi return true; } + public boolean visit(SQLSelectGroupByClause x) { + WallVisitorUtils.checkCondition(this, x.getHaving()); + return true; + } + + @Override + public boolean visit(SQLSelectQueryBlock x) { + WallVisitorUtils.checkCondition(this, x.getWhere()); + + return true; + } + + @Override + public boolean visit(OracleSelectQueryBlock x) { + return visit((SQLSelectQueryBlock) x); + } + @Override public boolean visit(SQLUnionQuery x) { if (WallVisitorUtils.queryBlockFromIsNull(x.getLeft()) || WallVisitorUtils.queryBlockFromIsNull(x.getRight())) { diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java index 86aafd5f1b..3208ea7285 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java @@ -16,6 +16,7 @@ import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; +import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; @@ -29,6 +30,7 @@ import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; @@ -50,7 +52,11 @@ public class WallVisitorUtils { } } - public static void check(WallVisitor visitor, SQLBinaryOpExpr x) { + public static void checkCondition(WallVisitor visitor, SQLExpr x) { + if (x == null) { + return; + } + if (Boolean.TRUE == getValue(x)) { visitor.getViolations().add(new IllegalSQLObjectViolation(SQLUtils.toSQLString(x))); } @@ -338,7 +344,8 @@ public class WallVisitorUtils { public static boolean queryBlockFromIsNull(SQLSelectQuery query) { if (query instanceof SQLSelectQueryBlock) { - SQLTableSource from = ((SQLSelectQueryBlock) query).getFrom(); + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; + SQLTableSource from = queryBlock.getFrom(); if (from == null) { return true; @@ -356,6 +363,26 @@ public class WallVisitorUtils { } } } + + if (queryBlock.getSelectList().size() == 1 && queryBlock.getSelectList().get(0).getExpr() instanceof SQLAllColumnExpr) { + if (from instanceof SQLSubqueryTableSource) { + SQLSelectQuery subQuery = ((SQLSubqueryTableSource) from).getSelect().getQuery(); + if (queryBlockFromIsNull(subQuery)) { + return true; + } + } + } + + boolean allIsConst = true; + for (SQLSelectItem item : queryBlock.getSelectList()) { + if (getValue(item.getExpr()) == null) { + allIsConst = false; + break; + } + } + if (allIsConst) { + return true; + } } return false; diff --git a/src/main/resources/META-INF/druid-filter-wall-permit-object.txt b/src/main/resources/META-INF/druid-filter-wall-permit-object.txt index 7c4274d959..fa113fe9e7 100644 --- a/src/main/resources/META-INF/druid-filter-wall-permit-object.txt +++ b/src/main/resources/META-INF/druid-filter-wall-permit-object.txt @@ -234,4 +234,6 @@ UTL_REF UTL_SMTP UTL_SPADV UTL_TCP -UTL_URL \ No newline at end of file +UTL_URL +SYS +SYSTEM \ No newline at end of file diff --git a/src/main/resources/META-INF/druid-filter-wall-permit-schema.txt b/src/main/resources/META-INF/druid-filter-wall-permit-schema.txt index 1710bf01ea..172fd0b599 100644 --- a/src/main/resources/META-INF/druid-filter-wall-permit-schema.txt +++ b/src/main/resources/META-INF/druid-filter-wall-permit-schema.txt @@ -1 +1,2 @@ -SYS \ No newline at end of file +SYS +SYSTEM \ No newline at end of file diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitObjectTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitObjectTest.java index 3813de4d97..853a3df0a8 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitObjectTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/OracleWallPermitObjectTest.java @@ -16,6 +16,7 @@ public class OracleWallPermitObjectTest extends TestCase { public void test_permitTable() throws Exception { Assert.assertFalse(WallUtils.isValidateOracle("select utl_inaddr.get_host_address from DUAL")); Assert.assertFalse(WallUtils.isValidateOracle("select TO_CHAR(utl_inaddr.get_host_address) from DUAL")); + Assert.assertFalse(WallUtils.isValidateOracle("SELECT SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT'.PUT(:P1));")); } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallHavingTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallHavingTest.java new file mode 100644 index 0000000000..d57e658b5f --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallHavingTest.java @@ -0,0 +1,24 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测可疑的Having条件 + * @author wenshao + * + */ +public class WallHavingTest extends TestCase { + private String sql = "SELECT F1, COUNT(*) FROM T GROUP BY F1 HAVING 1 = 1"; + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql)); + } + + public void testORACLE() throws Exception { + Assert.assertFalse(WallUtils.isValidateOracle(sql)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUnionTest4.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUnionTest4.java new file mode 100644 index 0000000000..fe0e711fbd --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUnionTest4.java @@ -0,0 +1,23 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,被攻击者用于测试当前SQL拥有多少字段 + * @author wenshao + * + */ +public class WallUnionTest4 extends TestCase { + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql("SELECT id, product FROM T1 t UNION (SELECT * FROM (SELECT 1,'x') X)")); + } + + public void testORACLE() throws Exception { + Assert.assertFalse(WallUtils.isValidateOracle("SELECT id, product FROM T1 t UNION (SELECT * FROM (SELECT 1,'x') X)")); + } +}