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:
@@ -77,6 +77,7 @@ import com.alibaba.druid.support.logging.LogFactory;
|
||||
import com.alibaba.druid.util.IOUtils;
|
||||
import com.alibaba.druid.util.JMXUtils;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
import com.alibaba.druid.wall.WallFilter;
|
||||
|
||||
/**
|
||||
* @author ljw<ljw2083@alibaba-inc.com>
|
||||
@@ -1440,8 +1441,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
ref.add(new StringRefAddr("instanceKey", instanceKey));
|
||||
ref.add(new StringRefAddr("url", this.getUrl()));
|
||||
ref.add(new StringRefAddr("username", this.getUsername()));
|
||||
ref.add(new StringRefAddr("password",this.getPassword()));
|
||||
//TODO ADD OTHER PROPERTIES
|
||||
ref.add(new StringRefAddr("password", this.getPassword()));
|
||||
// TODO ADD OTHER PROPERTIES
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -1946,6 +1947,17 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
return this.getDataSourceStat().getSqlStatMap();
|
||||
}
|
||||
|
||||
public Map<String, Object> getWallStatMap() {
|
||||
for (Filter filter : this.filters) {
|
||||
if (filter instanceof WallFilter) {
|
||||
WallFilter wallFilter = (WallFilter) filter;
|
||||
return wallFilter.getProvider().getStatsMap();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Lock getLock() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.sql.DriverManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -135,17 +136,17 @@ public final class DruidStatManagerFacade {
|
||||
|
||||
public List<Map<String, Object>> getSqlStatDataList(Integer dataSourceId) {
|
||||
Set<Object> dataSources = getDruidDataSourceInstances();
|
||||
|
||||
|
||||
if (dataSourceId == null) {
|
||||
List<Map<String, Object>> sqlList = new ArrayList<Map<String, Object>>();
|
||||
|
||||
|
||||
for (Object datasource : dataSources) {
|
||||
sqlList.addAll(getSqlStatDataList(datasource));
|
||||
}
|
||||
|
||||
|
||||
return sqlList;
|
||||
}
|
||||
|
||||
|
||||
for (Object datasource : dataSources) {
|
||||
if (dataSourceId != null && dataSourceId.intValue() != System.identityHashCode(datasource)) {
|
||||
continue;
|
||||
@@ -157,6 +158,62 @@ public final class DruidStatManagerFacade {
|
||||
return new ArrayList<Map<String, Object>>();
|
||||
}
|
||||
|
||||
public Map<String, Object> getWallStatMap(Integer dataSourceId) {
|
||||
Set<Object> dataSources = getDruidDataSourceInstances();
|
||||
|
||||
if (dataSourceId == null) {
|
||||
List<Map<String, Object>> sqlList = new ArrayList<Map<String, Object>>();
|
||||
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
for (Object datasource : dataSources) {
|
||||
Map<String, Object> wallStat = DruidDataSourceUtils.getWallStatMap(datasource);
|
||||
map = mergWallStat(map, wallStat);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
for (Object datasource : dataSources) {
|
||||
if (dataSourceId != null && dataSourceId.intValue() != System.identityHashCode(datasource)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return DruidDataSourceUtils.getWallStatMap(datasource);
|
||||
}
|
||||
|
||||
return new HashMap<String, Object>();
|
||||
//
|
||||
}
|
||||
|
||||
static Map mergWallStat(Map mapA, Map mapB) {
|
||||
if (mapA.size() == 0) {
|
||||
return mapB;
|
||||
}
|
||||
|
||||
if (mapB.size() == 0) {
|
||||
return mapA;
|
||||
}
|
||||
|
||||
for (Object item : mapB.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) item;
|
||||
String key = (String) entry.getKey();
|
||||
Object valueB = entry.getValue();
|
||||
Object valueA = mapA.get(key);
|
||||
|
||||
if (valueA == null) {
|
||||
mapA.put(key, valueB);
|
||||
} else {
|
||||
if (valueA instanceof Map && valueB instanceof Map) {
|
||||
Object newValue = mergWallStat((Map)valueA, (Map)valueB);
|
||||
mapA.put(key, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getSqlStatDataList(Object datasource) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
Map<?, ?> sqlStatMap = DruidDataSourceUtils.getSqlStatMap(datasource);
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.alibaba.druid.support.json.JSONUtils;
|
||||
import com.alibaba.druid.support.logging.Log;
|
||||
import com.alibaba.druid.support.logging.LogFactory;
|
||||
import com.alibaba.druid.support.spring.stat.SpringStatManager;
|
||||
import com.alibaba.druid.util.DruidDataSourceUtils;
|
||||
import com.alibaba.druid.util.MapComparator;
|
||||
import com.alibaba.druid.util.StringUtils;
|
||||
|
||||
@@ -256,6 +257,17 @@ public final class DruidStatService implements DruidStatServiceMBean {
|
||||
List<Map<String, Object>> sortedArray = comparatorOrderBy(array, parameters);
|
||||
return sortedArray;
|
||||
}
|
||||
|
||||
public Map<String, Object> getWallStatMap(Map<String, String> parameters) {
|
||||
Integer dataSourceId = null;
|
||||
|
||||
String dataSourceIdParam = parameters.get("dataSourceId");
|
||||
if (dataSourceIdParam != null && dataSourceIdParam.length() > 0) {
|
||||
dataSourceId = Integer.parseInt(dataSourceIdParam);
|
||||
}
|
||||
|
||||
return statManagerFacade.getWallStatMap(dataSourceId);
|
||||
}
|
||||
|
||||
private String getSqlStat(Integer id) {
|
||||
Map<String, Object> map = statManagerFacade.getSqlStatData(id);
|
||||
|
||||
@@ -167,6 +167,22 @@ public class DruidDataSourceUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static Map<String, Object> getWallStatMap(Object druidDatasource) {
|
||||
if (druidDatasource.getClass() == DruidDataSource.class) {
|
||||
return ((DruidDataSource) druidDatasource).getWallStatMap();
|
||||
}
|
||||
|
||||
try {
|
||||
Method method = druidDatasource.getClass().getMethod("getWallStatMap");
|
||||
Object obj = method.invoke(druidDatasource);
|
||||
return (Map) obj;
|
||||
} catch (Exception e) {
|
||||
LOG.error("getWallStatMap error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Map<String, Object>> getPoolingConnectionInfo(Object druidDatasource) {
|
||||
if (druidDatasource.getClass() == DruidDataSource.class) {
|
||||
|
||||
@@ -24,12 +24,33 @@ public class WallContext {
|
||||
|
||||
private WallSqlStat sqlState;
|
||||
private Map<String, WallSqlTableStat> tableStats;
|
||||
private Map<String, WallSqlFunctionStat> functionStats;
|
||||
private final String dbType;
|
||||
|
||||
public WallContext(String dbType){
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public void incrementFunctionInvoke(String tableName) {
|
||||
if (functionStats == null) {
|
||||
functionStats = new HashMap<String, WallSqlFunctionStat>();
|
||||
}
|
||||
|
||||
String lowerCaseName = tableName.toLowerCase();
|
||||
|
||||
WallSqlFunctionStat stat = functionStats.get(lowerCaseName);
|
||||
if (stat == null) {
|
||||
if (functionStats.size() > 100) {
|
||||
return;
|
||||
}
|
||||
|
||||
stat = new WallSqlFunctionStat();
|
||||
functionStats.put(tableName, stat);
|
||||
}
|
||||
|
||||
stat.incrementInvokeCount();
|
||||
}
|
||||
|
||||
public WallSqlTableStat getTableStat(String tableName) {
|
||||
if (tableStats == null) {
|
||||
tableStats = new HashMap<String, WallSqlTableStat>(2);
|
||||
@@ -39,7 +60,7 @@ public class WallContext {
|
||||
|
||||
WallSqlTableStat stat = tableStats.get(lowerCaseName);
|
||||
if (stat == null) {
|
||||
if (tableStats.size() > 10000) {
|
||||
if (tableStats.size() > 100) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -84,6 +105,10 @@ public class WallContext {
|
||||
return tableStats;
|
||||
}
|
||||
|
||||
public Map<String, WallSqlFunctionStat> getFunctionStats() {
|
||||
return functionStats;
|
||||
}
|
||||
|
||||
public String getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
public class WallFunctionStat {
|
||||
|
||||
private volatile long invokeCount;
|
||||
final static AtomicLongFieldUpdater<WallFunctionStat> invokeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallFunctionStat.class,
|
||||
"invokeCount");
|
||||
|
||||
public long getInvokeCount() {
|
||||
return invokeCount;
|
||||
}
|
||||
|
||||
public void incrementInvokeCount() {
|
||||
this.invokeCount++;
|
||||
}
|
||||
|
||||
public void addSqlFunctionStat(WallSqlFunctionStat sqlFunctionStat) {
|
||||
this.invokeCount += sqlFunctionStat.getInvokeCount();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,11 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -40,36 +43,33 @@ import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
|
||||
|
||||
public abstract class WallProvider {
|
||||
|
||||
private LRUCache<String, WallSqlStat> whiteList;
|
||||
private LRUCache<String, WallSqlStat> whiteList;
|
||||
|
||||
private int MAX_SQL_SIZE = 2048; // 1k
|
||||
private int MAX_SQL_LENGTH = 2048; // 1k
|
||||
|
||||
private int whiteSqlMaxLength = 1024; // 1k
|
||||
private int whiteSqlMaxSize = 1000; // 1k
|
||||
|
||||
private LRUCache<String, WallSqlStat> blackList;
|
||||
private LRUCache<String, WallSqlStat> blackList;
|
||||
|
||||
private int blackSqlMaxLength = 1024; // 1k
|
||||
private int blackSqlMaxSize = 1000; // 1k
|
||||
|
||||
protected final WallConfig config;
|
||||
protected final WallConfig config;
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
|
||||
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
|
||||
|
||||
private final ConcurrentMap<String, WallDenyStat> deniedTables = new ConcurrentHashMap<String, WallDenyStat>();
|
||||
private final ConcurrentMap<String, WallDenyStat> deniedFunctions = new ConcurrentHashMap<String, WallDenyStat>();
|
||||
private final ConcurrentMap<String, WallDenyStat> deniedSchemas = new ConcurrentHashMap<String, WallDenyStat>();
|
||||
private final ConcurrentMap<String, WallFunctionStat> functionStats = new ConcurrentHashMap<String, WallFunctionStat>();
|
||||
private final ConcurrentMap<String, WallTableStat> tableStats = new ConcurrentHashMap<String, WallTableStat>();
|
||||
|
||||
private final ConcurrentMap<String, WallTableStat> tableStats = new ConcurrentHashMap<String, WallTableStat>();
|
||||
public final WallDenyStat commentDeniedStat = new WallDenyStat();
|
||||
|
||||
public final WallDenyStat commentDeniedStat = new WallDenyStat();
|
||||
|
||||
protected String dbType = null;
|
||||
protected AtomicLong checkCount = new AtomicLong();
|
||||
protected AtomicLong whiteListHitCount = new AtomicLong();
|
||||
protected AtomicLong blackListHitCount = new AtomicLong();
|
||||
protected AtomicLong syntaxErrrorCount = new AtomicLong();
|
||||
protected AtomicLong violationCount = new AtomicLong();
|
||||
protected String dbType = null;
|
||||
protected final AtomicLong checkCount = new AtomicLong();
|
||||
protected final AtomicLong whiteListHitCount = new AtomicLong();
|
||||
protected final AtomicLong blackListHitCount = new AtomicLong();
|
||||
protected final AtomicLong syntaxErrrorCount = new AtomicLong();
|
||||
protected final AtomicLong violationCount = new AtomicLong();
|
||||
|
||||
public WallProvider(WallConfig config){
|
||||
this.config = config;
|
||||
@@ -82,9 +82,7 @@ public abstract class WallProvider {
|
||||
|
||||
public void reset() {
|
||||
this.clearWhiteList();
|
||||
this.deniedTables.clear();
|
||||
this.deniedFunctions.clear();
|
||||
this.deniedSchemas.clear();
|
||||
this.functionStats.clear();
|
||||
this.tableStats.clear();
|
||||
}
|
||||
|
||||
@@ -96,7 +94,7 @@ public abstract class WallProvider {
|
||||
String lowerCaseName = tableName.toLowerCase();
|
||||
return getTableStatWithLowerName(lowerCaseName);
|
||||
}
|
||||
|
||||
|
||||
public WallTableStat getTableStatWithLowerName(String lowerCaseName) {
|
||||
WallTableStat stat = tableStats.get(lowerCaseName);
|
||||
if (stat == null) {
|
||||
@@ -110,20 +108,39 @@ public abstract class WallProvider {
|
||||
return stat;
|
||||
}
|
||||
|
||||
public WallFunctionStat getFunctionStat(String functionName) {
|
||||
String lowerCaseName = functionName.toLowerCase();
|
||||
return getFunctionStatWithLowerName(lowerCaseName);
|
||||
}
|
||||
|
||||
public WallFunctionStat getFunctionStatWithLowerName(String lowerCaseName) {
|
||||
WallFunctionStat stat = functionStats.get(lowerCaseName);
|
||||
if (stat == null) {
|
||||
if (functionStats.size() > 10000) {
|
||||
return null;
|
||||
}
|
||||
|
||||
functionStats.putIfAbsent(lowerCaseName, new WallFunctionStat());
|
||||
stat = functionStats.get(lowerCaseName);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public WallConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public WallSqlStat addWhiteSql(String sql, Map<String, WallSqlTableStat> tableStats) {
|
||||
public WallSqlStat addWhiteSql(String sql, Map<String, WallSqlTableStat> tableStats,
|
||||
Map<String, WallSqlFunctionStat> functionStats) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (whiteList == null) {
|
||||
whiteList = new LRUCache<String, WallSqlStat>(whiteSqlMaxLength);
|
||||
whiteList = new LRUCache<String, WallSqlStat>(whiteSqlMaxSize);
|
||||
}
|
||||
|
||||
WallSqlStat wallStat = whiteList.get(sql);
|
||||
if (wallStat == null) {
|
||||
wallStat = new WallSqlStat(tableStats);
|
||||
wallStat = new WallSqlStat(tableStats, functionStats);
|
||||
whiteList.put(sql, wallStat);
|
||||
}
|
||||
|
||||
@@ -133,16 +150,17 @@ public abstract class WallProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public WallSqlStat addBlackSql(String sql, Map<String, WallSqlTableStat> tableStats, List<Violation> violations) {
|
||||
public WallSqlStat addBlackSql(String sql, Map<String, WallSqlTableStat> tableStats,
|
||||
Map<String, WallSqlFunctionStat> functionStats, List<Violation> violations) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (blackList == null) {
|
||||
blackList = new LRUCache<String, WallSqlStat>(blackSqlMaxLength);
|
||||
blackList = new LRUCache<String, WallSqlStat>(blackSqlMaxSize);
|
||||
}
|
||||
|
||||
WallSqlStat wallStat = blackList.get(sql);
|
||||
if (wallStat == null) {
|
||||
wallStat = new WallSqlStat(tableStats, violations);
|
||||
wallStat = new WallSqlStat(tableStats, functionStats, violations);
|
||||
blackList.put(sql, wallStat);
|
||||
}
|
||||
|
||||
@@ -256,13 +274,8 @@ public abstract class WallProvider {
|
||||
}
|
||||
|
||||
functionName = functionName.toLowerCase();
|
||||
|
||||
if (getConfig().getDenyFunctions().contains(functionName)) {
|
||||
WallDenyStat denyStat = this.deniedFunctions.get(functionName);
|
||||
if (denyStat == null) {
|
||||
this.deniedFunctions.putIfAbsent(functionName, new WallDenyStat());
|
||||
denyStat = this.deniedFunctions.get(functionName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -276,12 +289,6 @@ public abstract class WallProvider {
|
||||
|
||||
schemaName = schemaName.toLowerCase();
|
||||
if (getConfig().getDenySchemas().contains(schemaName)) {
|
||||
WallDenyStat denyStat = this.deniedSchemas.get(schemaName);
|
||||
if (denyStat == null) {
|
||||
this.deniedSchemas.putIfAbsent(schemaName, new WallDenyStat());
|
||||
denyStat = this.deniedSchemas.get(schemaName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -295,12 +302,6 @@ public abstract class WallProvider {
|
||||
|
||||
tableName = WallVisitorUtils.form(tableName);
|
||||
if (getConfig().getDenyTables().contains(tableName)) {
|
||||
WallDenyStat denyStat = this.deniedTables.get(tableName);
|
||||
if (denyStat == null) {
|
||||
this.deniedTables.putIfAbsent(tableName, new WallDenyStat());
|
||||
denyStat = this.deniedTables.get(tableName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -314,36 +315,12 @@ public abstract class WallProvider {
|
||||
|
||||
tableName = WallVisitorUtils.form(tableName);
|
||||
if (getConfig().isReadOnly(tableName)) {
|
||||
WallDenyStat denyStat = this.deniedTables.get(tableName);
|
||||
if (denyStat == null) {
|
||||
this.deniedTables.putIfAbsent(tableName, new WallDenyStat());
|
||||
denyStat = this.deniedTables.get(tableName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public WallDenyStat getDenniedTableStat(String tableName) {
|
||||
if (tableName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String formName = WallVisitorUtils.form(tableName);
|
||||
return deniedTables.get(formName);
|
||||
}
|
||||
|
||||
public WallDenyStat getDenniedSchemaStat(String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String formName = WallVisitorUtils.form(schemaName);
|
||||
return deniedSchemas.get(formName);
|
||||
}
|
||||
|
||||
public WallDenyStat getCommentDenyStat() {
|
||||
return this.commentDeniedStat;
|
||||
}
|
||||
@@ -384,16 +361,7 @@ public abstract class WallProvider {
|
||||
whiteListHitCount.incrementAndGet();
|
||||
sqlStat.incrementAndGetExecuteCount();
|
||||
|
||||
if (sqlStat.getTableStats() != null) {
|
||||
for (Map.Entry<String, WallSqlTableStat> entry : sqlStat.getTableStats().entrySet()) {
|
||||
String tableName = entry.getKey();
|
||||
WallSqlTableStat sqlTableStat = entry.getValue();
|
||||
WallTableStat tableStat = getTableStatWithLowerName(tableName);
|
||||
if (tableStat != null) {
|
||||
tableStat.addSqlTableStat(sqlTableStat);
|
||||
}
|
||||
}
|
||||
}
|
||||
recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -403,18 +371,7 @@ public abstract class WallProvider {
|
||||
if (sqlStat != null) {
|
||||
blackListHitCount.incrementAndGet();
|
||||
sqlStat.incrementAndGetExecuteCount();
|
||||
|
||||
if (sqlStat.getTableStats() != null) {
|
||||
for (Map.Entry<String, WallSqlTableStat> entry : sqlStat.getTableStats().entrySet()) {
|
||||
String tableName = entry.getKey();
|
||||
WallSqlTableStat sqlTableStat = entry.getValue();
|
||||
WallTableStat tableStat = getTableStat(tableName);
|
||||
if (tableStat != null) {
|
||||
tableStat.addSqlTableStat(sqlTableStat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats());
|
||||
List<Violation> blackViolations = sqlStat.getViolations();
|
||||
|
||||
result.getViolations().addAll(blackViolations);
|
||||
@@ -471,17 +428,25 @@ public abstract class WallProvider {
|
||||
if (result.getViolations().size() > 0) {
|
||||
violationCount.incrementAndGet();
|
||||
|
||||
if (sql.length() < MAX_SQL_SIZE) {
|
||||
addBlackSql(sql, context.getTableStats(), result.getViolations());
|
||||
if (sql.length() < MAX_SQL_LENGTH) {
|
||||
addBlackSql(sql, context.getTableStats(), context.getFunctionStats(), result.getViolations());
|
||||
}
|
||||
} else {
|
||||
if (sql.length() < MAX_SQL_SIZE) {
|
||||
addWhiteSql(sql, context.getTableStats());
|
||||
if (sql.length() < MAX_SQL_LENGTH) {
|
||||
addWhiteSql(sql, context.getTableStats(), context.getFunctionStats());
|
||||
}
|
||||
}
|
||||
|
||||
if (context != null && context.getTableStats() != null) {
|
||||
for (Map.Entry<String, WallSqlTableStat> entry : context.getTableStats().entrySet()) {
|
||||
if (context != null) {
|
||||
recordStats(context.getTableStats(), context.getFunctionStats());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void recordStats(Map<String, WallSqlTableStat> tableStats, Map<String, WallSqlFunctionStat> functionStats) {
|
||||
if (tableStats != null) {
|
||||
for (Map.Entry<String, WallSqlTableStat> entry : tableStats.entrySet()) {
|
||||
String tableName = entry.getKey();
|
||||
WallSqlTableStat sqlTableStat = entry.getValue();
|
||||
WallTableStat tableStat = getTableStat(tableName);
|
||||
@@ -490,8 +455,16 @@ public abstract class WallProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
if (functionStats != null) {
|
||||
for (Map.Entry<String, WallSqlFunctionStat> entry : functionStats.entrySet()) {
|
||||
String tableName = entry.getKey();
|
||||
WallSqlFunctionStat sqlTableStat = entry.getValue();
|
||||
WallFunctionStat functionStat = getFunctionStatWithLowerName(tableName);
|
||||
if (functionStat != null) {
|
||||
functionStat.addSqlFunctionStat(sqlTableStat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean ispPivileged() {
|
||||
@@ -541,8 +514,9 @@ public abstract class WallProvider {
|
||||
public long getViolationCount() {
|
||||
return violationCount.get();
|
||||
}
|
||||
|
||||
|
||||
public static class WallCommentHandler implements Lexer.CommentHandler {
|
||||
|
||||
public final static WallCommentHandler instance = new WallCommentHandler();
|
||||
|
||||
@Override
|
||||
@@ -550,7 +524,7 @@ public abstract class WallProvider {
|
||||
if (lastToken == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch (lastToken) {
|
||||
case SELECT:
|
||||
case INSERT:
|
||||
@@ -565,9 +539,42 @@ public abstract class WallProvider {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Map<String, Object> getStatsMap() {
|
||||
Map<String, Object> info = new LinkedHashMap<String, Object>();
|
||||
|
||||
info.put("checkCount", this.getCheckCount());
|
||||
info.put("violationCount", this.getViolationCount());
|
||||
info.put("blackListHitCount", this.getBlackListHitCount());
|
||||
info.put("blackListSize", this.getBlackList().size());
|
||||
info.put("whiteListHitCount", this.getWhiteListHitCount());
|
||||
info.put("whiteListSize", this.getWhiteList().size());
|
||||
info.put("syntaxErrrorCount", this.getSyntaxErrorCount());
|
||||
|
||||
{
|
||||
List<Map<String, Object>> tables = new ArrayList<Map<String, Object>>();
|
||||
for (Map.Entry<String, WallTableStat> entry : this.tableStats.entrySet()) {
|
||||
Map<String, Object> stat = new LinkedHashMap<String, Object>();
|
||||
stat.put("name", entry.getKey());
|
||||
entry.getValue().toMap(stat);
|
||||
tables.add(stat);
|
||||
}
|
||||
info.put("tables", tables);
|
||||
}
|
||||
{
|
||||
List<Map<String, Object>> functions = new ArrayList<Map<String, Object>>();
|
||||
for (Map.Entry<String, WallFunctionStat> entry : this.functionStats.entrySet()) {
|
||||
Map<String, Object> stat = new HashMap<String, Object>();
|
||||
stat.put("name", entry.getValue());
|
||||
stat.put("invokeCount", entry.getValue().getInvokeCount());
|
||||
functions.add(stat);
|
||||
}
|
||||
info.put("functions", functions);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
public class WallSqlFunctionStat {
|
||||
|
||||
private int invokeCount;
|
||||
|
||||
public int getInvokeCount() {
|
||||
return invokeCount;
|
||||
}
|
||||
|
||||
public void incrementInvokeCount() {
|
||||
this.invokeCount++;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,13 +30,17 @@ public class WallSqlStat {
|
||||
|
||||
private final List<Violation> violations;
|
||||
|
||||
public WallSqlStat(Map<String, WallSqlTableStat> tableStats){
|
||||
this(tableStats, Collections.<Violation> emptyList());
|
||||
private final Map<String, WallSqlFunctionStat> functionStats;
|
||||
|
||||
public WallSqlStat(Map<String, WallSqlTableStat> tableStats, Map<String, WallSqlFunctionStat> functionStats){
|
||||
this(tableStats, functionStats, Collections.<Violation> emptyList());
|
||||
}
|
||||
|
||||
public WallSqlStat(Map<String, WallSqlTableStat> tableStats, List<Violation> violations){
|
||||
public WallSqlStat(Map<String, WallSqlTableStat> tableStats, Map<String, WallSqlFunctionStat> functionStats,
|
||||
List<Violation> violations){
|
||||
this.violations = violations;
|
||||
this.tableStats = tableStats;
|
||||
this.functionStats = functionStats;
|
||||
}
|
||||
|
||||
public long incrementAndGetExecuteCount() {
|
||||
@@ -50,6 +54,10 @@ public class WallSqlStat {
|
||||
public Map<String, WallSqlTableStat> getTableStats() {
|
||||
return tableStats;
|
||||
}
|
||||
|
||||
public Map<String, WallSqlFunctionStat> getFunctionStats() {
|
||||
return functionStats;
|
||||
}
|
||||
|
||||
public List<Violation> getViolations() {
|
||||
return violations;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
@@ -151,7 +151,17 @@ public class WallTableStat {
|
||||
|
||||
public String toString() {
|
||||
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
Map<String, Object> map = toMap();
|
||||
|
||||
return JSONUtils.toJSONString(map);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
return toMap(map);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap(Map<String, Object> map) {
|
||||
if (selectCount > 0) {
|
||||
map.put("selectCount", selectCount);
|
||||
}
|
||||
@@ -176,7 +186,6 @@ public class WallTableStat {
|
||||
if (truncateCount > 0) {
|
||||
map.put("truncateCount", truncateCount);
|
||||
}
|
||||
|
||||
return JSONUtils.toJSONString(map);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,6 +799,11 @@ public class WallVisitorUtils {
|
||||
}
|
||||
|
||||
String methodName = x.getMethodName();
|
||||
|
||||
WallContext context = WallContext.current();
|
||||
if (context != null) {
|
||||
context.incrementFunctionInvoke(methodName);
|
||||
}
|
||||
|
||||
if (!visitor.getProvider().checkDenyFunction(methodName)) {
|
||||
addViolation(visitor, "deny function : " + methodName, x);
|
||||
|
||||
@@ -23,16 +23,14 @@ import com.alibaba.druid.wall.spi.OracleWallProvider;
|
||||
|
||||
/**
|
||||
* @author wenshao
|
||||
*
|
||||
*/
|
||||
public class WallDenySchemaTest extends TestCase {
|
||||
|
||||
public void testORACLE() throws Exception {
|
||||
String sql = "SELECT F1, F2 FROM ALL_ALL_TABLES";
|
||||
|
||||
|
||||
OracleWallProvider provider = new OracleWallProvider();
|
||||
Assert.assertFalse(provider.checkValid(sql));
|
||||
|
||||
Assert.assertEquals(1, provider.getDenniedTableStat("ALL_ALL_TABLES").getDenyCount());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,16 +23,14 @@ import com.alibaba.druid.wall.spi.OracleWallProvider;
|
||||
|
||||
/**
|
||||
* @author wenshao
|
||||
*
|
||||
*/
|
||||
public class WallDenyTableTest extends TestCase {
|
||||
|
||||
public void testORACLE() throws Exception {
|
||||
String sql = "SELECT F1, F2 FROM SYS.ABC";
|
||||
|
||||
|
||||
OracleWallProvider provider = new OracleWallProvider();
|
||||
Assert.assertFalse(provider.checkValid(sql));
|
||||
|
||||
Assert.assertEquals(1, provider.getDenniedSchemaStat("SYS").getDenyCount());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,18 @@ import com.alibaba.druid.wall.spi.OracleWallProvider;
|
||||
|
||||
/**
|
||||
* 这个场景,检测可疑的Having条件
|
||||
*
|
||||
* @author wenshao
|
||||
*
|
||||
*/
|
||||
public class WallReadOnlyTest2 extends TestCase {
|
||||
|
||||
private WallConfig config = new WallConfig();
|
||||
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
config.addReadOnlyTable("members");
|
||||
}
|
||||
private String sql = "SELECT F1, F2 members";
|
||||
|
||||
private String sql = "SELECT F1, F2 members";
|
||||
private String insert_sql = "INSERT INTO members (FID, FNAME) VALUES (?, ?)";
|
||||
private String update_sql = "UPDATE members SET FNAME = ? WHERe FID = ?";
|
||||
private String delete_sql = "DELETE members WHERE FID = ?";
|
||||
@@ -42,28 +44,20 @@ public class WallReadOnlyTest2 extends TestCase {
|
||||
public void testMySql() throws Exception {
|
||||
MySqlWallProvider provider = new MySqlWallProvider(config);
|
||||
Assert.assertTrue(provider.checkValid(sql));
|
||||
|
||||
Assert.assertNull(provider.getDenniedTableStat("members"));
|
||||
|
||||
|
||||
Assert.assertFalse(provider.checkValid(insert_sql));
|
||||
Assert.assertFalse(provider.checkValid(update_sql));
|
||||
Assert.assertFalse(provider.checkValid(delete_sql));
|
||||
|
||||
Assert.assertEquals(3, provider.getDenniedTableStat("members").getDenyCount());
|
||||
Assert.assertEquals(3, provider.getDenniedTableStat("Members").getDenyCount());
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testORACLE() throws Exception {
|
||||
OracleWallProvider provider = new OracleWallProvider(config);
|
||||
Assert.assertTrue(provider.checkValid(sql));
|
||||
|
||||
Assert.assertNull(provider.getDenniedTableStat("members"));
|
||||
|
||||
|
||||
Assert.assertFalse(provider.checkValid(insert_sql));
|
||||
Assert.assertFalse(provider.checkValid(update_sql));
|
||||
Assert.assertFalse(provider.checkValid(delete_sql));
|
||||
|
||||
Assert.assertEquals(3, provider.getDenniedTableStat("members").getDenyCount());
|
||||
Assert.assertEquals(3, provider.getDenniedTableStat("Members").getDenyCount());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.alibaba.druid.bvt.filter.wall;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.alibaba.druid.wall.WallContext;
|
||||
import com.alibaba.druid.wall.WallProvider;
|
||||
import com.alibaba.druid.wall.WallTableStat;
|
||||
import com.alibaba.druid.wall.spi.MySqlWallProvider;
|
||||
|
||||
public class WallStatTest_WhiteList extends TestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
|
||||
public void testMySql() throws Exception {
|
||||
WallProvider provider = new MySqlWallProvider();
|
||||
|
||||
for (int i = 0; i < 1001; ++i) {
|
||||
String sql = "select * from t where id = " + i;
|
||||
Assert.assertTrue(provider.checkValid(sql));
|
||||
}
|
||||
|
||||
WallTableStat tableStat = provider.getTableStat("t");
|
||||
Assert.assertEquals(1001, tableStat.getSelectCount());
|
||||
Assert.assertEquals(0, provider.getBlackListHitCount());
|
||||
Assert.assertEquals(0, provider.getWhiteListHitCount());
|
||||
Assert.assertEquals(1000, provider.getWhiteList().size());
|
||||
Assert.assertEquals(1001, provider.getCheckCount());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.alibaba.druid.bvt.filter.wall;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.alibaba.druid.wall.WallContext;
|
||||
import com.alibaba.druid.wall.WallProvider;
|
||||
import com.alibaba.druid.wall.WallTableStat;
|
||||
import com.alibaba.druid.wall.spi.MySqlWallProvider;
|
||||
|
||||
public class WallStatTest_blackList_1 extends TestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
|
||||
public void testMySql() throws Exception {
|
||||
WallProvider provider = new MySqlWallProvider();
|
||||
|
||||
for (int i = 0; i < 1001; ++i) {
|
||||
String sql = "select * from t where id = " + i + " OR 1 = 1";
|
||||
Assert.assertFalse(provider.checkValid(sql));
|
||||
}
|
||||
|
||||
WallTableStat tableStat = provider.getTableStat("t");
|
||||
Assert.assertEquals(1001, tableStat.getSelectCount());
|
||||
Assert.assertEquals(0, provider.getBlackListHitCount());
|
||||
Assert.assertEquals(0, provider.getWhiteListHitCount());
|
||||
Assert.assertEquals(0, provider.getWhiteList().size());
|
||||
Assert.assertEquals(1000, provider.getBlackList().size());
|
||||
Assert.assertEquals(1001, provider.getCheckCount());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.alibaba.druid.bvt.filter.wall;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.alibaba.druid.wall.WallContext;
|
||||
import com.alibaba.druid.wall.WallFunctionStat;
|
||||
import com.alibaba.druid.wall.WallProvider;
|
||||
import com.alibaba.druid.wall.WallTableStat;
|
||||
import com.alibaba.druid.wall.spi.MySqlWallProvider;
|
||||
|
||||
public class WallStatTest_function_stats extends TestCase {
|
||||
|
||||
private String sql = "select len(fname), len(fdesc) from t";
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
|
||||
public void testMySql() throws Exception {
|
||||
WallProvider provider = new MySqlWallProvider();
|
||||
Assert.assertTrue(provider.checkValid(sql));
|
||||
{
|
||||
WallTableStat tableStat = provider.getTableStat("t");
|
||||
Assert.assertEquals(1, tableStat.getSelectCount());
|
||||
}
|
||||
{
|
||||
WallFunctionStat functionStat = provider.getFunctionStat("len");
|
||||
Assert.assertEquals(2, functionStat.getInvokeCount());
|
||||
}
|
||||
Assert.assertTrue(provider.checkValid(sql));
|
||||
{
|
||||
WallTableStat tableStat = provider.getTableStat("t");
|
||||
Assert.assertEquals(2, tableStat.getSelectCount());
|
||||
}
|
||||
{
|
||||
WallFunctionStat functionStat = provider.getFunctionStat("len");
|
||||
Assert.assertEquals(4, functionStat.getInvokeCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.alibaba.druid.bvt.pool;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@@ -34,6 +36,8 @@ import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
|
||||
import com.alibaba.druid.spring.IUserService;
|
||||
import com.alibaba.druid.spring.User;
|
||||
import com.alibaba.druid.stat.DruidDataSourceStatManager;
|
||||
import com.alibaba.druid.stat.DruidStatService;
|
||||
import com.alibaba.druid.support.json.JSONUtils;
|
||||
|
||||
public class SpringIbatisFilterTest extends TestCase {
|
||||
|
||||
@@ -101,6 +105,11 @@ public class SpringIbatisFilterTest extends TestCase {
|
||||
conn.close();
|
||||
}
|
||||
|
||||
Assert.assertEquals(1, DruidDataSourceStatManager.getInstance().getDataSourceList().size());
|
||||
|
||||
Map<String, Object> wallStats = DruidStatService.getInstance().getWallStatMap(Collections.<String, String>emptyMap());
|
||||
|
||||
System.out.println("wall-stats : " + JSONUtils.toJSONString(wallStats));
|
||||
|
||||
context.close();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user