improved wallfilter. support update column check.

This commit is contained in:
wenshao
2017-08-14 16:09:35 +08:00
parent e1a6d99c1c
commit e210b1608a
22 changed files with 459 additions and 64 deletions
@@ -490,4 +490,22 @@ public class SQLBinaryOpExpr extends SQLExprImpl implements SQLReplaceable, Seri
return false;
}
public boolean conditionContainsColumn(String column) {
if (left == null || right == null) {
return false;
}
if (left instanceof SQLIdentifierExpr) {
if (((SQLIdentifierExpr) left).nameEquals(column)) {
return true;
}
} else if (right instanceof SQLIdentifierExpr) {
if (((SQLIdentifierExpr) right).nameEquals(column)) {
return true;
}
}
return false;
}
}
@@ -178,4 +178,8 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName {
return null;
}
public boolean nameEquals(String name) {
return SQLUtils.nameEquals(this.name, name);
}
}
@@ -199,4 +199,8 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName {
return null;
}
public boolean nameEquals(String name) {
return SQLUtils.nameEquals(this.name, name);
}
}
@@ -17,6 +17,8 @@ package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLUpdateSetItem extends SQLObjectImpl {
@@ -60,4 +62,12 @@ public class SQLUpdateSetItem extends SQLObjectImpl {
visitor.endVisit(this);
}
public boolean columnMatch(String column) {
if (this.column instanceof SQLIdentifierExpr) {
return ((SQLIdentifierExpr) this.column).nameEquals(column);
} else if (this.column instanceof SQLPropertyExpr) {
((SQLPropertyExpr) this.column).nameEquals(column);
}
return false;
}
}
@@ -58,8 +58,14 @@ public class SQLUpdateStatement extends SQLStatementImpl implements SQLReplaceab
public SQLName getTableName() {
if (tableSource instanceof SQLExprTableSource) {
SQLExprTableSource exprTableSource = (SQLExprTableSource) tableSource;
return (SQLName) exprTableSource.getExpr();
return ((SQLExprTableSource) tableSource).getName();
}
if (tableSource instanceof SQLJoinTableSource) {
SQLTableSource left = ((SQLJoinTableSource) tableSource).getLeft();
if (left instanceof SQLExprTableSource) {
return ((SQLExprTableSource) left).getName();
}
}
return null;
}
@@ -1395,8 +1395,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
setMode(x, Mode.Update);
SQLName identName = x.getTableName();
if (identName != null) {
SQLTableSource tableSource = x.getTableSource();
if (tableSource instanceof SQLExprTableSource) {
SQLName identName = ((SQLExprTableSource) tableSource).getName();
String ident = identName.toString();
setCurrentTable(ident);
@@ -1406,7 +1407,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
Map<String, String> aliasMap = getAliasMap();
putAliasMap(aliasMap, ident, ident);
} else {
x.getTableSource().accept(this);
tableSource.accept(this);
}
accept(x.getFrom());
@@ -22,7 +22,6 @@ import java.util.Map;
import com.alibaba.druid.sql.ast.SQLStatement;
public class WallCheckResult {
private final List<SQLStatement> statementList;
private final Map<String, WallSqlTableStat> tableStats;
@@ -36,6 +35,8 @@ public class WallCheckResult {
private String sql;
private List<WallUpdateCheckItem> updateCheckItems;
public WallCheckResult(){
this(null);
}
@@ -103,4 +104,12 @@ public class WallCheckResult {
public WallSqlStat getSqlStat() {
return sqlStat;
}
public List<WallUpdateCheckItem> getUpdateCheckItems() {
return updateCheckItems;
}
public void setUpdateCheckItems(List<WallUpdateCheckItem> updateCheckItems) {
this.updateCheckItems = updateCheckItems;
}
}
@@ -15,10 +15,10 @@
*/
package com.alibaba.druid.wall;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.wall.spi.WallVisitorUtils;
import java.util.Properties;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import static com.alibaba.druid.util.Utils.getBoolean;
@@ -129,6 +129,9 @@ public class WallConfig implements WallConfigMBean {
private int selectLimit = -1;
protected Map<String, Set<String>> updateCheckColumns = new HashMap<String, Set<String>>();
protected WallUpdateCheckHandler updateCheckHandler;
public WallConfig(){
this.configFromProperties(System.getProperties());
}
@@ -852,5 +855,53 @@ public class WallConfig implements WallConfigMBean {
this.setSelectLimit(propertyValue);
}
}
{
String propertyValue = properties.getProperty("druid.wall.updateCheckColumns");
if (propertyValue != null) {
String[] items = propertyValue.split(",");
for (String item : items) {
addUpdateCheckCoumns(item);
}
}
}
}
public void addUpdateCheckCoumns(String columnInfo) {
String[] items = columnInfo.split("\\.");
if (items.length != 2) {
return;
}
String table = SQLUtils.normalize(items[0]).toLowerCase();
String column = SQLUtils.normalize(items[1]).toLowerCase();
Set<String> columns = this.updateCheckColumns.get(table);
if (columns == null) {
columns = new LinkedHashSet<String>();
updateCheckColumns.put(table, columns);
}
columns.add(column);
}
public boolean isUpdateCheckTable(String tableName) {
if (updateCheckColumns.isEmpty()) {
return false;
}
String tableNameLower = SQLUtils.normalize(tableName).toLowerCase();
return updateCheckColumns.containsKey(tableNameLower);
}
public Set<String> getUpdateCheckTable(String tableName) {
if (updateCheckColumns.isEmpty()) {
return null;
}
String tableNameLower = SQLUtils.normalize(tableName).toLowerCase();
return updateCheckColumns.get(tableNameLower);
}
public WallUpdateCheckHandler getUpdateCheckHandler() {
return updateCheckHandler;
}
public void setUpdateCheckHandler(WallUpdateCheckHandler updateCheckHandler) {
this.updateCheckHandler = updateCheckHandler;
}
}
@@ -16,6 +16,7 @@
package com.alibaba.druid.wall;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WallContext {
@@ -33,6 +34,8 @@ public class WallContext {
private int deleteNoneConditionWarnings = 0;
private int likeNumberWarnings = 0;
private List<WallUpdateCheckItem> wallUpdateCheckItems;
public WallContext(String dbType){
this.dbType = dbType;
}
@@ -186,4 +189,11 @@ public class WallContext {
this.deleteNoneConditionWarnings++;
}
public List<WallUpdateCheckItem> getWallUpdateCheckItems() {
return wallUpdateCheckItems;
}
public void setWallUpdateCheckItems(List<WallUpdateCheckItem> wallUpdateCheckItems) {
this.wallUpdateCheckItems = wallUpdateCheckItems;
}
}
@@ -17,13 +17,10 @@ package com.alibaba.druid.wall;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.proxy.jdbc.CallableStatementProxy;
import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetMetaDataProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.alibaba.druid.proxy.jdbc.*;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
@@ -79,6 +76,7 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
private volatile boolean throwException = true;
public final static String ATTR_SQL_STAT = "wall.sqlStat";
public final static String ATTR_UPDATE_CHECK_ITEMS = "wall.updateCheckItems";
public WallFilter(){
configFromProperties(System.getProperties());
@@ -248,9 +246,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
PreparedStatementProxy stmt = chain.connection_prepareStatement(connection, sql);
setSqlStatAttribute(stmt);
return stmt;
@@ -263,9 +263,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int autoGeneratedKeys) throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
PreparedStatementProxy stmt = chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
setSqlStatAttribute(stmt);
return stmt;
@@ -279,9 +281,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
PreparedStatementProxy stmt = chain.connection_prepareStatement(connection, sql, resultSetType,
resultSetConcurrency);
setSqlStatAttribute(stmt);
@@ -296,9 +300,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
PreparedStatementProxy stmt = chain.connection_prepareStatement(connection, sql, resultSetType,
resultSetConcurrency, resultSetHoldability);
setSqlStatAttribute(stmt);
@@ -312,9 +318,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int[] columnIndexes) throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
PreparedStatementProxy stmt = chain.connection_prepareStatement(connection, sql, columnIndexes);
setSqlStatAttribute(stmt);
return stmt;
@@ -327,9 +335,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, String[] columnNames) throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
PreparedStatementProxy stmt = chain.connection_prepareStatement(connection, sql, columnNames);
setSqlStatAttribute(stmt);
return stmt;
@@ -342,9 +352,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
CallableStatementProxy stmt = chain.connection_prepareCall(connection, sql);
setSqlStatAttribute(stmt);
return stmt;
@@ -358,9 +370,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
int resultSetType, int resultSetConcurrency)
throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
CallableStatementProxy stmt = chain.connection_prepareCall(connection, sql, resultSetType,
resultSetConcurrency);
setSqlStatAttribute(stmt);
@@ -375,9 +389,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
String dbType = connection.getDirectDataSource().getDbType();
WallContext.create(dbType);
WallContext context = WallContext.create(dbType);
try {
sql = check(sql);
WallCheckResult result = checkInternal(sql);
context.setWallUpdateCheckItems(result.getUpdateCheckItems());
sql = result.getSql();
CallableStatementProxy stmt = chain.connection_prepareCall(connection, sql, resultSetType,
resultSetConcurrency, resultSetHoldability);
setSqlStatAttribute(stmt);
@@ -598,6 +614,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
@Override
public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
try {
wallUpdateCheck(statement);
boolean firstResult = chain.preparedStatement_execute(statement);
if (!firstResult) {
@@ -631,6 +649,8 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
@Override
public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
try {
wallUpdateCheck(statement);
int updateCount = chain.preparedStatement_executeUpdate(statement);
WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
if (sqlStat != null) {
@@ -643,6 +663,49 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
}
}
private void wallUpdateCheck(PreparedStatementProxy statement) throws SQLException {
Map<Integer, JdbcParameter> parameterMap = statement.getParameters();
List<WallUpdateCheckItem> wallUpdateCheckItems = (List<WallUpdateCheckItem>) statement.getAttribute(ATTR_UPDATE_CHECK_ITEMS);
if (wallUpdateCheckItems != null) {
for (WallUpdateCheckItem item : wallUpdateCheckItems) {
Object setValue;
if (item.value instanceof SQLValuableExpr) {
setValue = ((SQLValuableExpr) item.value).getValue();
} else {
int index = ((SQLVariantRefExpr) item.value).getIndex();
JdbcParameter parameter = parameterMap.get(index);
if (parameter != null) {
setValue = parameter.getValue();
} else {
setValue = null;
}
}
List<Object> filtersValues = new ArrayList<Object>(item.filterValues.size());
for (SQLExpr filterValueExpr : item.filterValues) {
Object filterValue;
if (filterValueExpr instanceof SQLValuableExpr) {
filterValue = ((SQLValuableExpr) filterValueExpr).getValue();
} else {
int index = ((SQLVariantRefExpr) filterValueExpr).getIndex();
JdbcParameter parameter = parameterMap.get(index);
if (parameter != null) {
filterValue = parameter.getValue();
} else {
filterValue = null;
}
}
filtersValues.add(filterValue);
}
boolean valid = config.updateCheckHandler.check(item.tableName, item.columnName, setValue, filtersValues);
if (!valid) {
throw new SQLException("wall update check failed.");
}
}
}
}
@Override
public ResultSetProxy statement_getResultSet(FilterChain chain, StatementProxy statement) throws SQLException {
ResultSetProxy resultSetProxy = chain.statement_getResultSet(statement);
@@ -669,6 +732,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
}
stmt.putAttribute(ATTR_SQL_STAT, sqlStat);
List<WallUpdateCheckItem> wallUpdateCheckItems = context.getWallUpdateCheckItems();
if (wallUpdateCheckItems != null) {
stmt.putAttribute(ATTR_UPDATE_CHECK_ITEMS, wallUpdateCheckItems);
}
}
public void statExecuteUpdate(int updateCount) {
@@ -709,6 +777,11 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
}
public String check(String sql) throws SQLException {
return checkInternal(sql)
.getSql();
}
private WallCheckResult checkInternal(String sql) throws SQLException {
WallCheckResult checkResult = provider.check(sql);
List<Violation> violations = checkResult.getViolations();
@@ -722,14 +795,14 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
if (violations.get(0) instanceof SyntaxErrorViolation) {
SyntaxErrorViolation violation = (SyntaxErrorViolation) violations.get(0);
throw new SQLException("sql injection violation, " + firstViolation.getMessage() + " : " + sql,
violation.getException());
violation.getException());
} else {
throw new SQLException("sql injection violation, " + firstViolation.getMessage() + " : " + sql);
}
}
}
return checkResult.getSql();
return checkResult;
}
@Override
@@ -704,6 +704,8 @@ public abstract class WallProvider {
}
result.setSql(resultSql);
result.setUpdateCheckItems(visitor.getUpdateCheckItems());
return result;
}
@@ -0,0 +1,25 @@
/*
* Copyright 1999-2017 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.List;
/**
* Created by wenshao on 13/08/2017.
*/
public interface WallUpdateCheckHandler {
boolean check(String table, String column, Object setValue, List<Object> filterValues);
}
@@ -0,0 +1,37 @@
/*
* Copyright 1999-2017 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 com.alibaba.druid.sql.ast.SQLExpr;
import java.util.List;
/**
* Created by wenshao on 14/08/2017.
*/
public class WallUpdateCheckItem {
public final String tableName;
public final String columnName;
public final SQLExpr value;
public final List<SQLExpr> filterValues;
public WallUpdateCheckItem(String tableName, String columnName, SQLExpr value, List<SQLExpr> filterValues) {
this.tableName = tableName;
this.columnName = columnName;
this.value = value;
this.filterValues = filterValues;
}
}
@@ -43,4 +43,8 @@ public interface WallVisitor extends SQLASTVisitor {
boolean isSqlEndOfComment();
void setSqlEndOfComment(boolean sqlEndOfComment);
void addWallUpdateCheckItem(WallUpdateCheckItem item);
List<WallUpdateCheckItem> getUpdateCheckItems();
}
@@ -28,10 +28,7 @@ import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitorAdapter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.Violation;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallProvider;
import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.*;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
@@ -45,6 +42,7 @@ public class DB2WallVisitor extends DB2ASTVisitorAdapter implements WallVisitor
private final List<Violation> violations = new ArrayList<Violation>();
private boolean sqlModified = false;
private boolean sqlEndOfComment = false;
private List<WallUpdateCheckItem> updateCheckItems;
public DB2WallVisitor(WallProvider provider){
this.config = provider.getConfig();
@@ -279,4 +277,15 @@ public class DB2WallVisitor extends DB2ASTVisitorAdapter implements WallVisitor
public void setSqlEndOfComment(boolean sqlEndOfComment) {
this.sqlEndOfComment = sqlEndOfComment;
}
public void addWallUpdateCheckItem(WallUpdateCheckItem item) {
if (updateCheckItems == null) {
updateCheckItems = new ArrayList<WallUpdateCheckItem>();
}
updateCheckItems.add(item);
}
public List<WallUpdateCheckItem> getUpdateCheckItems() {
return updateCheckItems;
}
}
@@ -42,12 +42,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.Violation;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallContext;
import com.alibaba.druid.wall.WallProvider;
import com.alibaba.druid.wall.WallSqlTableStat;
import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.*;
import com.alibaba.druid.wall.spi.WallVisitorUtils.WallTopStatementContext;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
@@ -59,6 +54,7 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
private final List<Violation> violations = new ArrayList<Violation>();
private boolean sqlModified = false;
private boolean sqlEndOfComment = false;
private List<WallUpdateCheckItem> updateCheckItems;
public MySqlWallVisitor(WallProvider provider){
this.config = provider.getConfig();
@@ -449,5 +445,15 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
public void setSqlEndOfComment(boolean sqlEndOfComment) {
this.sqlEndOfComment = sqlEndOfComment;
}
public void addWallUpdateCheckItem(WallUpdateCheckItem item) {
if (updateCheckItems == null) {
updateCheckItems = new ArrayList<WallUpdateCheckItem>();
}
updateCheckItems.add(item);
}
public List<WallUpdateCheckItem> getUpdateCheckItems() {
return updateCheckItems;
}
}
@@ -38,10 +38,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.Violation;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallProvider;
import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.*;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
@@ -52,6 +49,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
private final List<Violation> violations = new ArrayList<Violation>();
private boolean sqlModified = false;
private boolean sqlEndOfComment = false;
private List<WallUpdateCheckItem> updateCheckItems;
public OracleWallVisitor(WallProvider provider){
this.config = provider.getConfig();
@@ -345,4 +343,15 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
public void setSqlEndOfComment(boolean sqlEndOfComment) {
this.sqlEndOfComment = sqlEndOfComment;
}
public void addWallUpdateCheckItem(WallUpdateCheckItem item) {
if (updateCheckItems == null) {
updateCheckItems = new ArrayList<WallUpdateCheckItem>();
}
updateCheckItems.add(item);
}
public List<WallUpdateCheckItem> getUpdateCheckItems() {
return updateCheckItems;
}
}
@@ -29,10 +29,7 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitorAdapter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.Violation;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallProvider;
import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.*;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
@@ -46,6 +43,7 @@ public class PGWallVisitor extends PGASTVisitorAdapter implements WallVisitor {
private final List<Violation> violations = new ArrayList<Violation>();
private boolean sqlModified = false;
private boolean sqlEndOfComment = false;
private List<WallUpdateCheckItem> updateCheckItems;
public PGWallVisitor(WallProvider provider){
this.config = provider.getConfig();
@@ -302,4 +300,15 @@ public class PGWallVisitor extends PGASTVisitorAdapter implements WallVisitor {
public void setSqlEndOfComment(boolean sqlEndOfComment) {
this.sqlEndOfComment = sqlEndOfComment;
}
public void addWallUpdateCheckItem(WallUpdateCheckItem item) {
if (updateCheckItems == null) {
updateCheckItems = new ArrayList<WallUpdateCheckItem>();
}
updateCheckItems.add(item);
}
public List<WallUpdateCheckItem> getUpdateCheckItems() {
return updateCheckItems;
}
}
@@ -33,10 +33,7 @@ import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor;
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitorAdapter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.Violation;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallProvider;
import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.*;
import com.alibaba.druid.wall.spi.WallVisitorUtils.WallTopStatementContext;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
@@ -51,6 +48,7 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
private final List<Violation> violations = new ArrayList<Violation>();
private boolean sqlModified = false;
private boolean sqlEndOfComment = false;
private List<WallUpdateCheckItem> updateCheckItems;
public SQLServerWallVisitor(WallProvider provider){
this.config = provider.getConfig();
@@ -338,4 +336,15 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
public void setSqlEndOfComment(boolean sqlEndOfComment) {
this.sqlEndOfComment = sqlEndOfComment;
}
public void addWallUpdateCheckItem(WallUpdateCheckItem item) {
if (updateCheckItems == null) {
updateCheckItems = new ArrayList<WallUpdateCheckItem>();
}
updateCheckItems.add(item);
}
public List<WallUpdateCheckItem> getUpdateCheckItems() {
return updateCheckItems;
}
}
@@ -78,13 +78,9 @@ import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.util.ServletPathMatcher;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.*;
import com.alibaba.druid.wall.WallConfig.TenantCallBack;
import com.alibaba.druid.wall.WallConfig.TenantCallBack.StatementType;
import com.alibaba.druid.wall.WallContext;
import com.alibaba.druid.wall.WallProvider;
import com.alibaba.druid.wall.WallSqlTableStat;
import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
@@ -885,6 +881,10 @@ public class WallVisitorUtils {
return;
}
String tableName = x.getTableName().getSimpleName();
Set<String> updateCheckColumns = config.getUpdateCheckTable(tableName);
boolean isUpdateCheckTable = updateCheckColumns != null && !updateCheckColumns.isEmpty();
SQLExpr where = x.getWhere();
if (where == null) {
WallContext context = WallContext.current();
@@ -905,7 +905,6 @@ public class WallVisitorUtils {
}
}
} else {
where.setParent(x);
checkCondition(visitor, where);
if (Boolean.TRUE == getConditionValue(visitor, where, config.isUpdateWhereAlayTrueCheck())) {
@@ -913,6 +912,70 @@ public class WallVisitorUtils {
addViolation(visitor, ErrorCode.ALWAYS_TRUE, "update alway true condition not allow", x);
}
}
WallUpdateCheckHandler updateCheckHandler = config.getUpdateCheckHandler();
if (isUpdateCheckTable && updateCheckHandler != null) {
String checkColumn = updateCheckColumns.iterator().next();
SQLExpr valueExpr = null;
for (SQLUpdateSetItem item : x.getItems()) {
if (item.columnMatch(checkColumn)) {
valueExpr = item.getValue();
break;
}
}
if (valueExpr != null) {
List<SQLExpr> conditions;
if (where instanceof SQLBinaryOpExpr) {
conditions = SQLBinaryOpExpr.split((SQLBinaryOpExpr) where, SQLBinaryOperator.BooleanAnd);
} else {
conditions = new ArrayList<SQLExpr>();
conditions.add(where);
}
List<SQLExpr> filterValueExprList = new ArrayList<SQLExpr>();
for (SQLExpr condition : conditions) {
if (condition instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr binaryCondition = (SQLBinaryOpExpr) condition;
if (binaryCondition.getOperator() == SQLBinaryOperator.Equality
&& binaryCondition.conditionContainsColumn(checkColumn)) {
SQLExpr left = binaryCondition.getLeft();
SQLExpr right = binaryCondition.getRight();
if (left instanceof SQLValuableExpr || left instanceof SQLVariantRefExpr) {
filterValueExprList.add(left);
} else if (right instanceof SQLValuableExpr || right instanceof SQLVariantRefExpr) {
filterValueExprList.add(right);
}
}
}
}
boolean allValue = valueExpr instanceof SQLValuableExpr;
if (allValue) {
for (SQLExpr filterValue : filterValueExprList) {
if (!(filterValue instanceof SQLValuableExpr)) {
allValue = false;
break;
}
}
}
if (allValue) {
Object setValue = ((SQLValuableExpr) valueExpr).getValue();
List<Object> filterValues = new ArrayList<Object>(filterValueExprList.size());
for (SQLExpr expr : filterValueExprList) {
filterValues.add(((SQLValuableExpr) expr).getValue());
}
boolean validate = updateCheckHandler.check(tableName, checkColumn, setValue, filterValues);
visitor.addViolation(new IllegalSQLObjectViolation(ErrorCode.UPDATE_CHECK_FAIL, "update check failed.", visitor.toSQL(x)));
} else {
visitor.addWallUpdateCheckItem(new WallUpdateCheckItem(tableName, checkColumn, valueExpr, filterValueExprList));
}
//updateCheckHandler.check(tableName, checkColumn)
}
}
}
checkUpdateForMultiTenant(visitor, x);
@@ -85,5 +85,7 @@ public interface ErrorCode {
public final static int COMPOUND = 8000;
public final static int UPDATE_CHECK_FAIL = 9000;
public final static int OTHER = 9999;
}
@@ -0,0 +1,34 @@
package com.alibaba.druid.bvt.filter.wall;
import com.alibaba.druid.wall.WallCheckResult;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallUpdateCheckHandler;
import com.alibaba.druid.wall.spi.MySqlWallProvider;
import junit.framework.TestCase;
import java.util.List;
import java.util.Properties;
/**
* Created by wenshao on 13/08/2017.
*/
public class WallUpdateCheckTest extends TestCase {
private MySqlWallProvider wallProvider = new MySqlWallProvider();
protected void setUp() throws Exception {
Properties properties = new Properties();
properties.put("druid.wall.updateCheckColumns", "t_orders.status");
wallProvider.getConfig().configFromProperties(properties);
wallProvider.getConfig().setUpdateCheckHandler(new WallUpdateCheckHandler() {
@Override
public boolean check(String table, String column, Object setValue, List<Object> filterValues) {
return false;
}
});
}
public void test_update_check_handler() throws Exception {
WallCheckResult result = wallProvider.check("update t_orders set status = 3 where id = 3 and status = 4");
assertTrue(result.getViolations().size() > 0);
}
}