This commit is contained in:
wenshao
2013-03-18 10:13:40 +08:00
32 changed files with 719 additions and 167 deletions
@@ -17,69 +17,69 @@ package com.alibaba.druid.wall;
import static com.alibaba.druid.wall.spi.WallVisitorUtils.loadResource;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import com.alibaba.druid.wall.spi.WallVisitorUtils;
public class WallConfig implements WallConfigMBean {
private boolean noneBaseStatementAllow = false;
private boolean noneBaseStatementAllow = false;
private boolean callAllow = true;
private boolean selelctAllow = true;
private boolean selectIntoAllow = true;
private boolean selectIntoOutfileAllow = false;
private boolean selectWhereAlwayTrueCheck = true;
private boolean selectHavingAlwayTrueCheck = true;
private boolean selectUnionCheck = true;
private boolean callAllow = true;
private boolean selelctAllow = true;
private boolean selectIntoAllow = true;
private boolean selectIntoOutfileAllow = false;
private boolean selectWhereAlwayTrueCheck = true;
private boolean selectHavingAlwayTrueCheck = true;
private boolean selectUnionCheck = true;
private boolean selectAllColumnAllow = true;
private boolean selectAllColumnAllow = true;
private boolean deleteAllow = true;
private boolean deleteWhereAlwayTrueCheck = true;
private boolean deleteAllow = true;
private boolean deleteWhereAlwayTrueCheck = true;
private boolean updateAllow = true;
private boolean updateWhereAlayTrueCheck = true;
private boolean updateAllow = true;
private boolean updateWhereAlayTrueCheck = true;
private boolean insertAllow = true;
private boolean mergeAllow = true;
private boolean insertAllow = true;
private boolean mergeAllow = true;
private boolean multiStatementAllow = false;
private boolean multiStatementAllow = false;
private boolean truncateAllow = false;
private boolean truncateAllow = false;
private boolean commentAllow = false;
private boolean commentAllow = false;
private boolean describeAllow = false;
private boolean describeAllow = false;
private boolean schemaCheck = true;
private boolean tableCheck = true;
private boolean functionCheck = true;
private boolean objectCheck = true;
private boolean variantCheck = true;
private boolean schemaCheck = true;
private boolean tableCheck = true;
private boolean functionCheck = true;
private boolean objectCheck = true;
private boolean variantCheck = true;
private boolean mustParameterized = false;
private boolean mustParameterized = false;
private boolean doPrivilegedAllow = false;
private boolean doPrivilegedAllow = false;
protected final Set<String> permitFunctions = new HashSet<String>();
protected final Set<String> permitTables = new HashSet<String>();
protected final Set<String> permitSchemas = new HashSet<String>();
protected final Set<String> permitVariants = new HashSet<String>();
protected final Set<String> permitObjects = new HashSet<String>();
protected final Set<String> denyFunctions = new ConcurrentSkipListSet<String>();
protected final Set<String> denyTables = new ConcurrentSkipListSet<String>();
protected final Set<String> denySchemas = new ConcurrentSkipListSet<String>();
protected final Set<String> denyVariants = new ConcurrentSkipListSet<String>();
protected final Set<String> denyObjects = new ConcurrentSkipListSet<String>();
protected final Set<String> readOnlyTables = new HashSet<String>();
protected final Set<String> readOnlyTables = new ConcurrentSkipListSet<String>();
private String dir;
private String dir;
private boolean inited;
private boolean inited;
private String tenantTablePattern;
private String tenantColumn;
private String tenantTablePattern;
private String tenantColumn;
private boolean wrapAllow = true;
private boolean metadataAllow = true;
private boolean wrapAllow = true;
private boolean metadataAllow = true;
public WallConfig(){
@@ -159,11 +159,11 @@ public class WallConfig implements WallConfigMBean {
dir = dir.substring(0, dir.length() - 1);
}
loadResource(this.permitVariants, dir + "/permit-variant.txt");
loadResource(this.permitSchemas, dir + "/permit-schema.txt");
loadResource(this.permitFunctions, dir + "/permit-function.txt");
loadResource(this.permitTables, dir + "/permit-table.txt");
loadResource(this.permitObjects, dir + "/permit-object.txt");
loadResource(this.denyVariants, dir + "/deny-variant.txt");
loadResource(this.denySchemas, dir + "/deny-schema.txt");
loadResource(this.denyFunctions, dir + "/deny-function.txt");
loadResource(this.denyTables, dir + "/deny-table.txt");
loadResource(this.denyObjects, dir + "/deny-object.txt");
loadResource(this.readOnlyTables, dir + "/readonly-table.txt");
}
@@ -357,30 +357,38 @@ public class WallConfig implements WallConfigMBean {
this.commentAllow = commentAllow;
}
public Set<String> getPermitFunctions() {
return permitFunctions;
public Set<String> getDenyFunctions() {
return denyFunctions;
}
public Set<String> getPermitTables() {
return permitTables;
public Set<String> getDenyTables() {
return denyTables;
}
public Set<String> getPermitSchemas() {
return permitSchemas;
public Set<String> getDenySchemas() {
return denySchemas;
}
public Set<String> getPermitVariants() {
return permitVariants;
public Set<String> getDenyVariants() {
return denyVariants;
}
public Set<String> getPermitObjects() {
return permitObjects;
public Set<String> getDenyObjects() {
return denyObjects;
}
public Set<String> getReadOnlyTables() {
return readOnlyTables;
}
public void addReadOnlyTable(String tableName) {
this.readOnlyTables.add(tableName);
}
public boolean isReadOnly(String tableName) {
return this.readOnlyTables.contains(tableName);
}
public boolean isMustParameterized() {
return mustParameterized;
}
@@ -389,31 +397,31 @@ public class WallConfig implements WallConfigMBean {
this.mustParameterized = mustParameterized;
}
public boolean isPermitObjects(String name) {
public boolean isDenyObjects(String name) {
if (!objectCheck) {
return false;
}
name = WallVisitorUtils.form(name);
return permitObjects.contains(name);
return denyObjects.contains(name);
}
public boolean isPermitSchema(String name) {
public boolean isDenySchema(String name) {
if (!schemaCheck) {
return false;
}
name = WallVisitorUtils.form(name);
return this.permitSchemas.contains(name);
return this.denySchemas.contains(name);
}
public boolean isPermitFunction(String name) {
public boolean isDenyFunction(String name) {
if (!functionCheck) {
return false;
}
name = WallVisitorUtils.form(name);
return this.permitFunctions.contains(name);
return this.denyFunctions.contains(name);
}
public boolean isCallAllow() {
@@ -113,22 +113,22 @@ public interface WallConfigMBean {
void setCommentAllow(boolean commentAllow);
Set<String> getPermitFunctions();
Set<String> getDenyFunctions();
Set<String> getPermitTables();
Set<String> getDenyTables();
Set<String> getPermitSchemas();
Set<String> getDenySchemas();
Set<String> getPermitVariants();
Set<String> getDenyVariants();
Set<String> getPermitObjects();
Set<String> getDenyObjects();
Set<String> getReadOnlyTables();
boolean isPermitObjects(String name);
boolean isDenyObjects(String name);
boolean isPermitSchema(String name);
boolean isDenySchema(String name);
boolean isPermitFunction(String name);
boolean isDenyFunction(String name);
}
@@ -0,0 +1,34 @@
package com.alibaba.druid.wall;
public class WallContext {
private final static ThreadLocal<WallContext> contextLocal = new ThreadLocal<WallContext>();
private WallSqlStat sqlState;
public static WallContext createIfNotExists() {
WallContext context = contextLocal.get();
if (context == null) {
context = new WallContext();
contextLocal.set(context);
}
return context;
}
public static WallContext current() {
return contextLocal.get();
}
public static void clearContext() {
contextLocal.remove();
}
public WallSqlStat getSqlState() {
return sqlState;
}
public void setSqlState(WallSqlStat sqlState) {
this.sqlState = sqlState;
}
}
@@ -0,0 +1,46 @@
package com.alibaba.druid.wall;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class WallDenyStat {
private volatile long denyCount;
private volatile long lastDenyTimeMillis;
private volatile long resetCount;
final static AtomicLongFieldUpdater<WallDenyStat> denyCountUpdater = AtomicLongFieldUpdater.newUpdater(WallDenyStat.class,
"denyCount");
final static AtomicLongFieldUpdater<WallDenyStat> resetCountUpdater = AtomicLongFieldUpdater.newUpdater(WallDenyStat.class,
"resetCount");
public long incrementAndGetDenyCount() {
lastDenyTimeMillis = System.currentTimeMillis();
return denyCountUpdater.incrementAndGet(this);
}
public long getDenyCount() {
return denyCount;
}
public Date getLastDenyTime() {
if (lastDenyTimeMillis <= 0) {
return null;
}
return new Date(lastDenyTimeMillis);
}
public void reset() {
lastDenyTimeMillis = 0;
denyCount = 0;
resetCountUpdater.incrementAndGet(this);
}
public long getResetCount() {
return this.resetCount;
}
}
@@ -37,7 +37,7 @@ import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.wall.spi.MySqlWallProvider;
import com.alibaba.druid.wall.spi.OracleWallProvider;
import com.alibaba.druid.wall.spi.SQLServerProvider;
import com.alibaba.druid.wall.spi.SQLServerWallProvider;
import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
public class WallFilter extends FilterAdapter implements WallFilterMBean {
@@ -86,10 +86,10 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
provider = new OracleWallProvider(config);
} else if (JdbcUtils.SQL_SERVER.equals(dbType) || JdbcUtils.JTDS.equals(dbType)) {
if (config == null) {
config = new WallConfig(SQLServerProvider.DEFAULT_CONFIG_DIR);
config = new WallConfig(SQLServerWallProvider.DEFAULT_CONFIG_DIR);
}
provider = new SQLServerProvider(config);
provider = new SQLServerWallProvider(config);
} else {
throw new IllegalStateException("dbType not support : " + dbType + ", url " + dataSource.getUrl());
}
@@ -159,139 +159,235 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
@Override
public void statement_addBatch(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
sql = check(sql);
chain.statement_addBatch(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
chain.statement_addBatch(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int autoGeneratedKeys) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int[] columnIndexes) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnIndexes);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnIndexes);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, String[] columnNames) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnNames);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnNames);
} finally {
WallContext.clearContext();
}
}
@Override
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
sql = check(sql);
return chain.connection_prepareCall(connection, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareCall(connection, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
int resultSetType, int resultSetConcurrency)
throws SQLException {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
} finally {
WallContext.clearContext();
}
}
@Override
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
} finally {
WallContext.clearContext();
}
}
// //////////////
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql, autoGeneratedKeys);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql, autoGeneratedKeys);
} finally {
WallContext.clearContext();
}
}
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql, columnIndexes);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql, columnIndexes);
} finally {
WallContext.clearContext();
}
}
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql, columnNames);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql, columnNames);
} finally {
WallContext.clearContext();
}
}
@Override
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
throws SQLException {
sql = check(sql);
return chain.statement_executeQuery(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeQuery(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnIndexes);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnIndexes);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnNames);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnNames);
} finally {
WallContext.clearContext();
}
}
public String check(String sql) throws SQLException {
@@ -355,7 +451,7 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
if (isLogViolation()) {
LOG.error("not support method : Connection.getMetdataData");
}
if (throwException) {
throw new WallSQLException("not support method : Connection.getMetdataData");
} else {
@@ -369,4 +465,16 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public long getViolationCount() {
return this.violationCount.get();
}
public void resetViolationCount() {
this.violationCount.set(0);
}
public void clearWhiteList() {
this.provider.clearCache();
}
public boolean checkValid(String sql) {
return provider.checkValid(sql);
}
}
@@ -39,4 +39,10 @@ public interface WallFilterMBean {
String check(String sql) throws SQLException;
long getViolationCount();
void resetViolationCount();
void clearWhiteList();
boolean checkValid(String sql);
}
@@ -19,33 +19,40 @@ import java.security.PrivilegedAction;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.parser.NotAllowCommentException;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.sql.visitor.ExportParameterVisitor;
import com.alibaba.druid.util.LRUCache;
import com.alibaba.druid.wall.spi.WallVisitorUtils;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
public abstract class WallProvider {
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
private LinkedHashMap<String, WallSqlStat> whiteList;
private LinkedHashMap<String, Object> whiteList;
private int whileListMaxSize = 1024;
private int whileListMaxSize = 1024;
private int whiteSqlMaxLength = 1024; // 1k
private int whiteSqlMaxLength = 1024; // 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>();
public final WallDenyStat commentDeniedStat = new WallDenyStat();
public WallProvider(WallConfig config){
this.config = config;
@@ -59,10 +66,10 @@ public abstract class WallProvider {
lock.writeLock().lock();
try {
if (whiteList == null) {
whiteList = new LRUCache<String, Object>(whileListMaxSize);
whiteList = new LRUCache<String, WallSqlStat>(whileListMaxSize);
}
whiteList.put(sql, PRESENT);
whiteList.put(sql, new WallSqlStat());
} finally {
lock.writeLock().unlock();
}
@@ -83,6 +90,10 @@ public abstract class WallProvider {
}
public void clearCache() {
clearWhiteList();
}
public void clearWhiteList() {
lock.writeLock().lock();
try {
if (whiteList != null) {
@@ -93,19 +104,23 @@ public abstract class WallProvider {
}
}
public boolean whiteContains(String sql) {
public WallSqlStat getWhiteSql(String sql) {
lock.readLock().lock();
try {
if (whiteList == null) {
return false;
return null;
}
return whiteList.get(sql) != null;
return whiteList.get(sql);
} finally {
lock.readLock().unlock();
}
}
public boolean whiteContains(String sql) {
return getWhiteSql(sql) != null;
}
public abstract SQLStatementParser createParser(String sql);
public abstract WallVisitor createWallVisitor();
@@ -113,7 +128,110 @@ public abstract class WallProvider {
public abstract ExportParameterVisitor createExportParameterVisitor();
public boolean checkValid(String sql) {
return check(sql).getViolations().isEmpty();
WallCheckResult result = check(sql);
return result.getViolations().isEmpty();
}
public void incrementCommentDeniedCount() {
this.commentDeniedStat.incrementAndGetDenyCount();
}
public boolean checkDenyFunction(String functionName) {
if (functionName == null) {
return true;
}
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;
}
return true;
}
public boolean checkDenySchema(String schemaName) {
if (schemaName == null) {
return true;
}
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;
}
return true;
}
public boolean checkDenyTable(String tableName) {
if (tableName == null) {
return true;
}
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;
}
return true;
}
public boolean checkReadOnlyTable(String tableName) {
if (tableName == null) {
return true;
}
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;
}
public WallCheckResult check(String sql) {
@@ -124,19 +242,24 @@ public abstract class WallProvider {
}
// first step, check whiteList
boolean isWhite = whiteContains(sql);
if (isWhite) {
WallSqlStat sqlStat = getWhiteSql(sql);
if (sqlStat != null) {
sqlStat.incrementAndGetExecuteCount();
return result;
}
SQLStatementParser parser = createParser(sql);
if (!config.isCommentAllow()) {
parser.getLexer().setAllowComment(false); // permit comment
parser.getLexer().setAllowComment(false); // deny comment
}
try {
parser.parseStatementList(result.getStatementList());
} catch (NotAllowCommentException e) {
result.getViolations().add(new SyntaxErrorViolation(e, sql));
incrementCommentDeniedCount();
return result;
} catch (Exception e) {
result.getViolations().add(new SyntaxErrorViolation(e, sql));
return result;
@@ -176,13 +299,13 @@ public abstract class WallProvider {
result.getViolations().addAll(visitor.getViolations());
return result;
}
public static boolean ispPivileged() {
Boolean value = privileged.get();
if (value == null) {
return false;
}
return value.booleanValue();
}
@@ -0,0 +1,20 @@
package com.alibaba.druid.wall;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class WallSqlStat {
private volatile long executeCount;
final static AtomicLongFieldUpdater<WallSqlStat> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"executeCount");
public long incrementAndGetExecuteCount() {
return executeCountUpdater.incrementAndGet(this);
}
public long getExecuteCount() {
return executeCount;
}
}
@@ -17,7 +17,7 @@ package com.alibaba.druid.wall;
import com.alibaba.druid.wall.spi.MySqlWallProvider;
import com.alibaba.druid.wall.spi.OracleWallProvider;
import com.alibaba.druid.wall.spi.SQLServerProvider;
import com.alibaba.druid.wall.spi.SQLServerWallProvider;
public class WallUtils {
@@ -42,12 +42,12 @@ public class WallUtils {
}
public static boolean isValidateSqlServer(String sql) {
SQLServerProvider provider = new SQLServerProvider();
SQLServerWallProvider provider = new SQLServerWallProvider();
return provider.checkValid(sql);
}
public static boolean isValidateSqlServer(String sql, WallConfig config) {
SQLServerProvider provider = new SQLServerProvider(config);
SQLServerWallProvider provider = new SQLServerWallProvider(config);
return provider.checkValid(sql);
}
}
@@ -30,7 +30,7 @@ public interface WallVisitor extends SQLASTVisitor {
void addViolation(Violation violation);
boolean isPermitTable(String name);
boolean isDenyTable(String name);
String toSQL(SQLObject obj);
}
@@ -237,13 +237,12 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
}
@Override
public boolean isPermitTable(String name) {
public boolean isDenyTable(String name) {
if (!config.isTableCheck()) {
return false;
}
name = WallVisitorUtils.form(name);
return config.getPermitTables().contains(name);
return !this.provider.checkDenyTable(name);
}
public void preVisit(SQLObject x) {
@@ -83,7 +83,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
public boolean visit(SQLIdentifierExpr x) {
String name = x.getName();
name = WallVisitorUtils.form(name);
if (config.isVariantCheck() && config.getPermitVariants().contains(name)) {
if (config.isVariantCheck() && config.getDenyVariants().contains(name)) {
getViolations().add(new IllegalSQLObjectViolation(toSQL(x)));
}
return true;
@@ -112,8 +112,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
}
public boolean visit(OracleSelectTableReference x) {
WallVisitorUtils.check(this, x);
return true;
return WallVisitorUtils.check(this, x);
}
public boolean visit(SQLExprTableSource x) {
@@ -158,7 +157,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
}
@Override
public boolean isPermitTable(String name) {
public boolean isDenyTable(String name) {
if (!config.isTableCheck()) {
return false;
}
@@ -167,7 +166,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
if (name.startsWith("v$") || name.startsWith("v_$")) {
return true;
}
return config.getPermitTables().contains(name);
return !this.provider.checkDenyTable(name);
}
public void preVisit(SQLObject x) {
@@ -30,18 +30,18 @@ import com.alibaba.druid.wall.WallVisitor;
* @version 1.0, 2012-3-17
* @see
*/
public class SQLServerProvider extends WallProvider {
public class SQLServerWallProvider extends WallProvider {
public final static String DEFAULT_CONFIG_DIR = "META-INF/druid/wall/sqlserver";
/**
* @param config
*/
public SQLServerProvider(){
public SQLServerWallProvider(){
this(new WallConfig(DEFAULT_CONFIG_DIR));
}
public SQLServerProvider(WallConfig config){
public SQLServerWallProvider(WallConfig config){
super(config);
}
@@ -80,13 +80,12 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
}
@Override
public boolean isPermitTable(String name) {
public boolean isDenyTable(String name) {
if (!config.isTableCheck()) {
return false;
}
name = WallVisitorUtils.form(name);
return config.getPermitTables().contains(name);
return !this.provider.checkDenyTable(name);
}
@Override
@@ -97,7 +96,7 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
public boolean visit(SQLIdentifierExpr x) {
String name = x.getName();
name = WallVisitorUtils.form(name);
if (config.isVariantCheck() && config.getPermitVariants().contains(name)) {
if (config.isVariantCheck() && config.getDenyVariants().contains(name)) {
getViolations().add(new IllegalSQLObjectViolation(toSQL(x)));
}
return true;
@@ -238,10 +237,10 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
@Override
public boolean visit(SQLServerObjectReferenceExpr x) {
if (x.getSchema() != null && config.isPermitSchema(x.getSchema())) {
if (x.getSchema() != null && !provider.checkDenySchema(x.getSchema())) {
this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x)));
}
if (x.getDatabase() != null && config.isPermitSchema(x.getDatabase())) {
if (x.getDatabase() != null && !provider.checkDenySchema(x.getDatabase())) {
this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x)));
}
return true;
@@ -69,7 +69,7 @@ import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
public class WallVisitorUtils {
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
public static void check(WallVisitor visitor, SQLInListExpr x) {
@@ -348,11 +348,9 @@ public class WallVisitorUtils {
tableName = ((SQLName) tableNameExpr).getSimleName();
}
if (tableName != null) {
tableName = form(tableName);
if (visitor.getConfig().getReadOnlyTables().contains(tableName)) {
addViolation(visitor, tableSource);
}
boolean readOnlyValid = visitor.getProvider().checkReadOnlyTable(tableName);
if (!readOnlyValid) {
addViolation(visitor, tableSource);
}
} else if (tableSource instanceof SQLJoinTableSource) {
SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
@@ -777,44 +775,54 @@ public class WallVisitorUtils {
String methodName = x.getMethodName();
if (visitor.getConfig().isPermitFunction(methodName.toLowerCase())) {
if (!visitor.getProvider().checkDenyFunction(methodName)) {
addViolation(visitor, x);
}
}
private static void checkSchema(WallVisitor visitor, SQLExpr x) {
private static boolean checkSchema(WallVisitor visitor, SQLExpr x) {
if (x instanceof SQLName) {
String owner = ((SQLName) x).getSimleName();
owner = WallVisitorUtils.form(owner);
if (visitor.getConfig().isPermitSchema(owner)) {
if (!visitor.getProvider().checkDenySchema(owner)) {
addViolation(visitor, x);
return false;
}
if (visitor.getConfig().isPermitObjects(owner)) {
if (visitor.getConfig().isDenyObjects(owner)) {
addViolation(visitor, x);
return false;
}
}
// if (ownerExpr instanceof SQLPropertyExpr) {
if (x instanceof SQLPropertyExpr) {
checkSchema(visitor, ((SQLPropertyExpr) x).getOwner());
return checkSchema(visitor, ((SQLPropertyExpr) x).getOwner());
}
return true;
}
public static void check(WallVisitor visitor, SQLExprTableSource x) {
public static boolean check(WallVisitor visitor, SQLExprTableSource x) {
SQLExpr expr = x.getExpr();
if (expr instanceof SQLPropertyExpr) {
checkSchema(visitor, ((SQLPropertyExpr) expr).getOwner());
boolean checkResult = checkSchema(visitor, ((SQLPropertyExpr) expr).getOwner());
if (!checkResult) {
return false;
}
}
if (expr instanceof SQLName) {
String tableName = ((SQLName) expr).getSimleName();
if (visitor.isPermitTable(tableName)) {
if (visitor.isDenyTable(tableName)) {
addViolation(visitor, x);
return false;
}
}
return true;
}
private static void addViolation(WallVisitor visitor, SQLObject x) {
@@ -919,7 +927,7 @@ public class WallVisitorUtils {
}
}
} catch (IOException e) {
LOG.error("load oracle permit tables errror", e);
LOG.error("load oracle deny tables errror", e);
}
}
}