mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improve wall filter
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,24 +210,30 @@ public final class DruidStatManagerFacade {
|
||||
} else if (valueB == null) {
|
||||
newMap.put(key, valueA);
|
||||
} else if ("blackList".equals(key)) {
|
||||
Set<String> newSet = new HashSet<String>();
|
||||
Map<String, Map<String, Object>> newSet = new HashMap<String, Map<String, Object>>();
|
||||
|
||||
Collection<String> collectionA = (Collection<String>) valueA;
|
||||
for (String blackItem : collectionA) {
|
||||
Collection<Map<String, Object>> collectionA = (Collection<Map<String, Object>>) valueA;
|
||||
for (Map<String, Object> blackItem : collectionA) {
|
||||
if (newSet.size() >= 1000) {
|
||||
break;
|
||||
}
|
||||
newSet.add(blackItem);
|
||||
|
||||
String sql = (String) blackItem.get("sql");
|
||||
Map<String, Object> oldItem = newSet.get(sql);
|
||||
newSet.put(sql, mergWallStat(oldItem, blackItem));
|
||||
}
|
||||
|
||||
Collection<String> collectionB = (Collection<String>) valueB;
|
||||
for (String blackItem : collectionB) {
|
||||
Collection<Map<String, Object>> collectionB = (Collection<Map<String, Object>>) valueB;
|
||||
for (Map<String, Object> blackItem : collectionB) {
|
||||
if (newSet.size() >= 1000) {
|
||||
break;
|
||||
}
|
||||
newSet.add(blackItem);
|
||||
|
||||
String sql = (String) blackItem.get("sql");
|
||||
Map<String, Object> 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<Map<String, Object>> 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);
|
||||
|
||||
@@ -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.<String> unmodifiableSet(hashSet);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getBlackListStat() {
|
||||
List<Map<String, Object>> map = new ArrayList<Map<String, Object>>();
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
if (blackList != null) {
|
||||
for (Map.Entry<String, WallSqlStat> entry : this.blackList.entrySet()) {
|
||||
WallSqlStat sqlStat = entry.getValue();
|
||||
|
||||
Map<String, Object> sqlStatMap = new LinkedHashMap<String, Object>();
|
||||
sqlStatMap.put("sql", entry.getKey());
|
||||
sqlStatMap.put("executeCount", sqlStat.getExecuteCount());
|
||||
|
||||
List<Violation> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-14
@@ -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; "));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<String>) statMapMerged.get("blackList")).size());
|
||||
Assert.assertEquals(2, ((Collection<Map<String, Object>>) statMapMerged.get("blackList")).size());
|
||||
|
||||
statMapMerged = DruidStatManagerFacade.mergWallStat(statMapMerged, statMapC);
|
||||
System.out.println(JSONUtils.toJSONString(statMapMerged));
|
||||
Assert.assertEquals(2, ((Collection<String>) statMapMerged.get("blackList")).size());
|
||||
Assert.assertEquals(2, ((Collection<Map<String, Object>>) statMapMerged.get("blackList")).size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user