diff --git a/src/main/java/com/alibaba/druid/filter/wall/WallFilter.java b/src/main/java/com/alibaba/druid/filter/wall/WallFilter.java index 102c07c8b3..ce54acf4c2 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/WallFilter.java +++ b/src/main/java/com/alibaba/druid/filter/wall/WallFilter.java @@ -3,6 +3,7 @@ package com.alibaba.druid.filter.wall; import java.sql.SQLException; import java.util.Properties; +import com.alibaba.druid.DruidRuntimeException; import com.alibaba.druid.filter.FilterAdapter; import com.alibaba.druid.filter.FilterChain; import com.alibaba.druid.filter.wall.spi.MySqlWallProvider; @@ -17,13 +18,45 @@ import com.alibaba.druid.util.JdbcUtils; public class WallFilter extends FilterAdapter { + private boolean inited = false; + private WallProvider provider; + private boolean loadDefault; + + private boolean loadExtend; + @Override public void init(DataSourceProxy dataSource) { this.dataSource = dataSource; provider = createWallProvider(dataSource.getDbType()); + + this.inited = true; + } + + public boolean isLoadDefault() { + return loadDefault; + } + + public void checkInit() { + if (inited) { + throw new DruidRuntimeException("wall filter is inited"); + } + } + + public void setLoadDefault(boolean loadDefault) { + checkInit(); + this.loadDefault = loadDefault; + } + + public boolean isLoadExtend() { + return loadExtend; + } + + public void setLoadExtend(boolean loadExtend) { + checkInit(); + this.loadExtend = loadExtend; } @Override @@ -168,11 +201,11 @@ public class WallFilter extends FilterAdapter { public WallProvider createWallProvider(String dbType) { if (JdbcUtils.MYSQL.equals(dbType)) { - return new MySqlWallProvider(); + return new MySqlWallProvider(this.loadDefault, this.loadExtend); } if (JdbcUtils.ORACLE.equals(dbType)) { - return new OracleWallProvider(); + return new OracleWallProvider(this.loadDefault, this.loadExtend); } throw new IllegalStateException("dbType not support : " + dbType); diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallProvider.java b/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallProvider.java index 66a3f7d9f5..165a731727 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallProvider.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallProvider.java @@ -8,19 +8,32 @@ import com.alibaba.druid.sql.parser.SQLStatementParser; public class MySqlWallProvider extends WallProvider { public MySqlWallProvider(){ - loadDefault(); - + this(true, true); + } + + public MySqlWallProvider(boolean loadDefault, boolean loadExtend){ + if (loadDefault) { + loadDefault(); + } + + if (loadExtend) { + loadExtend(); + } + } + + public void loadExtend() { WallVisitorUtils.loadResource(this.permitNames, "META-INF/druid-filter-wall-permit-name-mysql.txt"); WallVisitorUtils.loadResource(this.permitSchemas, "META-INF/druid-filter-wall-permit-schema-mysql.txt"); WallVisitorUtils.loadResource(this.permitFunctions, "META-INF/druid-filter-wall-permit-function-mysql.txt"); WallVisitorUtils.loadResource(this.permitTables, "META-INF/druid-filter-wall-permit-table-mysql.txt"); WallVisitorUtils.loadResource(this.permitObjects, "META-INF/druid-filter-wall-permit-object-mysql.txt"); } - + public void loadDefault() { WallVisitorUtils.loadResource(this.permitNames, "META-INF/druid-filter-wall-permit-name-mysql-default.txt"); WallVisitorUtils.loadResource(this.permitSchemas, "META-INF/druid-filter-wall-permit-schema-mysql-default.txt"); - WallVisitorUtils.loadResource(this.permitFunctions, "META-INF/druid-filter-wall-permit-function-mysql-default.txt"); + WallVisitorUtils.loadResource(this.permitFunctions, + "META-INF/druid-filter-wall-permit-function-mysql-default.txt"); WallVisitorUtils.loadResource(this.permitTables, "META-INF/druid-filter-wall-permit-table-mysql-default.txt"); WallVisitorUtils.loadResource(this.permitObjects, "META-INF/druid-filter-wall-permit-object-mysql-default.txt"); } diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallProvider.java b/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallProvider.java index d0bca28324..7297724789 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallProvider.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallProvider.java @@ -8,8 +8,20 @@ import com.alibaba.druid.sql.parser.SQLStatementParser; public class OracleWallProvider extends WallProvider { public OracleWallProvider(){ - loadDefault(); + this(true, true); + } + public OracleWallProvider(boolean loadDefault, boolean loadExtend){ + if (loadDefault) { + loadDefault(); + } + + if (loadExtend) { + loadExtend(); + } + } + + public void loadExtend() { WallVisitorUtils.loadResource(this.permitNames, "META-INF/druid-filter-wall-permit-name-oracle.txt"); WallVisitorUtils.loadResource(this.permitSchemas, "META-INF/druid-filter-wall-permit-schema-oracle.txt"); WallVisitorUtils.loadResource(this.permitFunctions, "META-INF/druid-filter-wall-permit-function-oracle.txt"); @@ -17,6 +29,15 @@ public class OracleWallProvider extends WallProvider { WallVisitorUtils.loadResource(this.permitObjects, "META-INF/druid-filter-wall-permit-object-oracle.txt"); } + public void loadDefault() { + WallVisitorUtils.loadResource(this.permitNames, "META-INF/druid-filter-wall-permit-name-oracle-default.txt"); + WallVisitorUtils.loadResource(this.permitSchemas, "META-INF/druid-filter-wall-permit-schema-oracle-default.txt"); + WallVisitorUtils.loadResource(this.permitFunctions, + "META-INF/druid-filter-wall-permit-function-oracle-default.txt"); + WallVisitorUtils.loadResource(this.permitTables, "META-INF/druid-filter-wall-permit-table-oracle-default.txt"); + WallVisitorUtils.loadResource(this.permitObjects, "META-INF/druid-filter-wall-permit-object-oracle-default.txt"); + } + @Override public SQLStatementParser createParser(String sql) { return new OracleStatementParser(sql); @@ -27,12 +48,4 @@ public class OracleWallProvider extends WallProvider { return new OracleWallVisitor(this); } - public void loadDefault() { - WallVisitorUtils.loadResource(this.permitNames, "META-INF/druid-filter-wall-permit-name-oracle-default.txt"); - WallVisitorUtils.loadResource(this.permitSchemas, "META-INF/druid-filter-wall-permit-schema-oracle-default.txt"); - WallVisitorUtils.loadResource(this.permitFunctions, - "META-INF/druid-filter-wall-permit-function-oracle-default.txt"); - WallVisitorUtils.loadResource(this.permitTables, "META-INF/druid-filter-wall-permit-table-oracle-default.txt"); - WallVisitorUtils.loadResource(this.permitObjects, "META-INF/druid-filter-wall-permit-object-oracle-default.txt"); - } } 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 8cd5ca8085..9bc08ef3f5 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 @@ -41,7 +41,7 @@ import com.alibaba.druid.util.JdbcUtils; public class WallVisitorUtils { private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class); - + public static void check(WallVisitor visitor, SQLPropertyExpr x) { if (x.getOwner() instanceof SQLIdentifierExpr) { String owner = x.getOwner().toString(); @@ -56,7 +56,7 @@ public class WallVisitorUtils { if (x == null) { return; } - + if (Boolean.TRUE == getValue(x)) { visitor.getViolations().add(new IllegalSQLObjectViolation(SQLUtils.toSQLString(x))); } @@ -85,15 +85,32 @@ 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; + } + + } + } + + if (leftResult == null || rightResult == null) { + return null; + } + if (x.getOperator() == SQLBinaryOperator.Equality) { if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) { return true; } - if (leftResult == null || rightResult == null) { - return null; - } - return leftResult.equals(rightResult); } @@ -165,21 +182,8 @@ 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; - } - - } + if (x.getOperator() == SQLBinaryOperator.Concat) { + return leftResult.toString() + rightResult.toString(); } return null; @@ -252,6 +256,30 @@ public class WallVisitorUtils { } } + if ("chr".equalsIgnoreCase(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; + + return "" + ch; + } + } + + if ("concat".equalsIgnoreCase(methodName)) { + StringBuffer buf = new StringBuffer(); + for (SQLExpr expr : x.getParameters()) { + Object value = getValue(expr); + if (value == null) { + return null; + } + + buf.append(value.toString()); + } + return buf.toString(); + } + return null; } @@ -302,6 +330,14 @@ public class WallVisitorUtils { } public static void check(WallVisitor visitor, SQLMethodInvokeExpr x) { + if (x.getOwner() instanceof SQLIdentifierExpr) { + String owner = x.getOwner().toString(); + owner = WallVisitorUtils.form(owner); + if (visitor.containsPermitObjects(owner)) { + visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x))); + } + } + String methodName = x.getMethodName(); if (visitor.getWallProvider().getPermitFunctions().contains(methodName.toLowerCase())) { @@ -363,8 +399,9 @@ public class WallVisitorUtils { } } } - - if (queryBlock.getSelectList().size() == 1 && queryBlock.getSelectList().get(0).getExpr() instanceof SQLAllColumnExpr) { + + 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)) { @@ -372,7 +409,7 @@ public class WallVisitorUtils { } } } - + boolean allIsConst = true; for (SQLSelectItem item : queryBlock.getSelectList()) { if (getValue(item.getExpr()) == null) { 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 853a3df0a8..9777b6a9c4 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 @@ -14,9 +14,12 @@ import com.alibaba.druid.filter.wall.WallUtils; public class OracleWallPermitObjectTest extends TestCase { public void test_permitTable() throws Exception { + Assert.assertFalse(WallUtils.isValidateOracle("select sys.LinxReadFile('c:/boot.ini') from dual")); + Assert.assertFalse(WallUtils.isValidateOracle("select sys.LinxRunCMD('cmd /c net user linx /add') from dual")); 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));")); + Assert.assertFalse(WallUtils.isValidateOracle("select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES()")); } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest3.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest3.java new file mode 100644 index 0000000000..b5001ee521 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest3.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 WallSelectWhereTest3 extends TestCase { + private String sql = "select * from t WHERE FID = 256 AND CHR(67)||CHR(65)||CHR(84) = 'CAT'"; + + public void testMySql() throws Exception { + Assert.assertTrue(WallUtils.isValidateMySql(sql)); + } + + public void testORACLE() throws Exception { + Assert.assertTrue(WallUtils.isValidateOracle(sql)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.java new file mode 100644 index 0000000000..c8fd2fbdd7 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.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 WallSelectWhereTest4 extends TestCase { + private String sql = "select * from t WHERE FID = 256 OR CHR(67)||CHR(65)||CHR(84) = 'CAT'"; + + 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/WallSelectWhereTest5.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest5.java new file mode 100644 index 0000000000..d80589909b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest5.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 WallSelectWhereTest5 extends TestCase { + private String sql = "select * from t WHERE FID = 256 OR CONCAT(CHR(67)||CHR(65)||CHR(84), '-DOG') = 'CAT-DOG'"; + + 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/WallVisitorUtilsTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallVisitorUtilsTest.java index 49cc7a0ce2..20956cd203 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallVisitorUtilsTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallVisitorUtilsTest.java @@ -18,23 +18,31 @@ public class WallVisitorUtilsTest extends TestCase { Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("f1 like '%%'"))); Assert.assertEquals(null, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("a1 = b1 AND f1 like '%%'"))); Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("a1 = b1 OR f1 like '%%'"))); - + Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("1 < 2"))); Assert.assertEquals(Boolean.FALSE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("2 < 2"))); Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("2 <= 2"))); - + Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("2 > 1"))); Assert.assertEquals(Boolean.FALSE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("2 > 2"))); Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("2 >= 2"))); - + Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("len('44') > 0"))); Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("len('44') >= 2"))); - + Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("(select count(*) from t) > 0"))); - Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("(select count(*) from t) >= 0"))); - Assert.assertEquals(Boolean.FALSE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("(select count(*) from t) < 0"))); - Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("NOT (select count(*) from t) < 0"))); - + Assert.assertEquals(Boolean.TRUE, + WallVisitorUtils.getValue(SQLUtils.toSQLExpr("(select count(*) from t) >= 0"))); + Assert.assertEquals(Boolean.FALSE, + WallVisitorUtils.getValue(SQLUtils.toSQLExpr("(select count(*) from t) < 0"))); + Assert.assertEquals(Boolean.TRUE, + WallVisitorUtils.getValue(SQLUtils.toSQLExpr("NOT (select count(*) from t) < 0"))); + // } + + public void test_chr() throws Exception { + Assert.assertEquals("CAT", WallVisitorUtils.getValue(SQLUtils.toSQLExpr("CHR(67)||CHR(65)||CHR(84)"))); + Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("CHR(67)||CHR(65)||CHR(84) = 'CAT'"))); + } }