add sql wall support

This commit is contained in:
温少
2012-03-15 23:09:35 +08:00
parent 5ddff762bd
commit f238b25361
10 changed files with 1509 additions and 39 deletions
@@ -5,6 +5,7 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
public abstract class WallProvider {
@@ -48,6 +49,13 @@ public abstract class WallProvider {
parser.getLexer().setAllowComment(false); // permit comment
List<SQLStatement> statementList = parser.parseStatementList();
if(parser.getLexer().token() != Token.EOF) {
if (throwException) {
throw new WallRuntimeException("illegal statement : " + sql);
}
return false;
}
if (statementList.size() > 1) {
if (throwException) {
throw new WallRuntimeException("multi-statement : " + sql);
@@ -1,6 +1,7 @@
package com.alibaba.druid.filter.wall;
import com.alibaba.druid.filter.wall.spi.MySqlWallProvider;
import com.alibaba.druid.filter.wall.spi.OracleWallProvider;
public class WallUtils {
@@ -8,4 +9,9 @@ public class WallUtils {
MySqlWallProvider provider = new MySqlWallProvider();
return provider.check(sql, false);
}
public static boolean isValidateOracle(String sql) {
OracleWallProvider provider = new OracleWallProvider();
return provider.check(sql, false);
}
}
@@ -1,10 +1,24 @@
package com.alibaba.druid.filter.wall;
import java.util.List;
import java.util.Set;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public interface WallVisitor extends SQLASTVisitor {
List<Violation> getViolations();
Set<String> getPermitFunctions();
Set<String> getPermitSchemas();
Set<String> getPermitTables();
boolean containsPermitTable(String name);
Set<String> getPermitNames();
String toSQL(SQLObject obj);
}
@@ -9,15 +9,13 @@ import com.alibaba.druid.filter.wall.IllegalSQLObjectViolation;
import com.alibaba.druid.filter.wall.Violation;
import com.alibaba.druid.filter.wall.WallVisitor;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr;
@@ -30,9 +28,10 @@ import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisitor {
private Set<String> permitFunctions = new HashSet<String>();
private Set<String> permitTablesoures = new HashSet<String>();
private Set<String> permitSchemas = new HashSet<String>();
private final Set<String> permitFunctions = new HashSet<String>();
private final Set<String> permitTables = new HashSet<String>();
private final Set<String> permitSchemas = new HashSet<String>();
private final Set<String> permiNames = new HashSet<String>();
private final List<Violation> violations;
@@ -40,6 +39,22 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
this(new ArrayList<Violation>());
}
public Set<String> getPermitNames() {
return permiNames;
}
public Set<String> getPermitFunctions() {
return permitFunctions;
}
public Set<String> getPermitTables() {
return permitTables;
}
public Set<String> getPermitSchemas() {
return permitSchemas;
}
public MySqlWallVisitor(List<Violation> violations){
this.violations = violations;
@@ -57,7 +72,7 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
permitSchemas.add("information_schema");
permitSchemas.add("mysql");
permitTablesoures.add("outfile");
permitTables.add("outfile");
}
public List<Violation> getViolations() {
@@ -127,28 +142,16 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
@Override
public boolean visit(SQLMethodInvokeExpr x) {
String methodName = x.getMethodName();
if (permitFunctions.contains(methodName.toLowerCase())) {
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
}
WallVisitorUtils.check(this, x);
return true;
}
public boolean visit(SQLExprTableSource x) {
SQLExpr expr = x.getExpr();
WallVisitorUtils.check(this, x);
if (expr instanceof SQLPropertyExpr) {
SQLPropertyExpr propExpr = (SQLPropertyExpr) expr;
if (propExpr.getOwner() instanceof SQLIdentifierExpr) {
String ownerName = ((SQLIdentifierExpr) propExpr.getOwner()).getName();
if (permitSchemas.contains(ownerName.toLowerCase())) {
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
}
}
if (x.getExpr() instanceof SQLName) {
return false;
}
return true;
@@ -162,18 +165,22 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
@Override
public boolean visit(SQLUnionQuery x) {
if (queryBlockFromIsNull(x.getLeft()) || queryBlockFromIsNull(x.getRight())) {
if (WallVisitorUtils.queryBlockFromIsNull(x.getLeft()) || WallVisitorUtils.queryBlockFromIsNull(x.getRight())) {
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
}
return true;
}
private static boolean queryBlockFromIsNull(SQLSelectQuery query) {
if (query instanceof SQLSelectQueryBlock) {
return ((SQLSelectQueryBlock) query).getFrom() == null;
}
return false;
@Override
public String toSQL(SQLObject obj) {
return SQLUtils.toMySqlString(obj);
}
@Override
public boolean containsPermitTable(String name) {
name = WallVisitorUtils.form(name);
return permitTables.contains(name);
}
}
@@ -1,18 +1,43 @@
package com.alibaba.druid.filter.wall.spi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.alibaba.druid.filter.wall.IllegalSQLObjectViolation;
import com.alibaba.druid.filter.wall.Violation;
import com.alibaba.druid.filter.wall.WallVisitor;
import com.alibaba.druid.logging.Log;
import com.alibaba.druid.logging.LogFactory;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVIsitorAdapter;
import com.alibaba.druid.util.JdbcUtils;
public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVisitor {
private final static Log LOG = LogFactory.getLog(OracleWallVisitor.class);
private final Set<String> permitFunctions = new HashSet<String>();
private final Set<String> permitTables = new HashSet<String>();
private final Set<String> permitSchemas = new HashSet<String>();
private final Set<String> permitNames = new HashSet<String>();
private final List<Violation> violations;
public OracleWallVisitor(){
@@ -21,20 +46,143 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi
public OracleWallVisitor(List<Violation> violations){
this.violations = violations;
addPermitFunction("sys_context");
addPermitFunction("userenv");
addPermitFunction("sys_guid");
addPermitFunction("sys_typeid");
addPermitName("uid");
addPermitName("user");
loadPermitTables();
}
private void loadPermitTables() {
try {
Enumeration<URL> e = Thread.currentThread().getContextClassLoader().getResources("META-INF/druid-filter-wall-permit-function.txt");
while (e.hasMoreElements()) {
URL url = e.nextElement();
InputStream in = null;
BufferedReader reader = null;
try {
in = url.openStream();
reader = new BufferedReader(new InputStreamReader(in));
for (;;) {
String line = reader.readLine();
if (line == null) {
break;
}
line = line.trim();
if (line.length() > 0) {
addPermitTable(line);
}
}
url.openStream();
} finally {
JdbcUtils.close(reader);
JdbcUtils.close(in);
}
}
} catch (IOException e) {
LOG.error("load oracle permit tables errror", e);
}
}
public void addPermitName(String name) {
name = name.toLowerCase();
permitNames.add(name);
}
public void addPermitFunction(String name) {
name = name.toLowerCase();
permitFunctions.add(name);
}
public void addPermitTable(String name) {
name = name.toLowerCase();
permitTables.add(name);
}
public Set<String> getPermitNames() {
return permitNames;
}
public Set<String> getPermitFunctions() {
return permitFunctions;
}
public Set<String> getPermitTables() {
return permitTables;
}
public Set<String> getPermitSchemas() {
return permitSchemas;
}
public List<Violation> getViolations() {
return violations;
}
public boolean visit(SQLIdentifierExpr x) {
return true;
}
// executeQuery
public boolean visit(SQLBinaryOpExpr x) {
WallVisitorUtils.check(this, x);
return true;
}
public boolean visit(SQLDropTableStatement x) {
violations.add(new IllegalSQLObjectViolation(SQLUtils.toOracleString(x)));
return false;
}
@Override
public boolean visit(SQLMethodInvokeExpr x) {
WallVisitorUtils.check(this, x);
return true;
}
public boolean visit(OracleSelectTableReference x) {
WallVisitorUtils.check(this, x);
return true;
}
public boolean visit(SQLExprTableSource x) {
WallVisitorUtils.check(this, x);
if (x.getExpr() instanceof SQLName) {
return false;
}
return true;
}
@Override
public boolean visit(SQLUnionQuery x) {
if (WallVisitorUtils.queryBlockFromIsNull(x.getLeft()) || WallVisitorUtils.queryBlockFromIsNull(x.getRight())) {
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
}
return true;
}
@Override
public String toSQL(SQLObject obj) {
return SQLUtils.toOracleString(obj);
}
@Override
public boolean containsPermitTable(String name) {
name = WallVisitorUtils.form(name);
return permitTables.contains(name);
}
}
@@ -4,16 +4,20 @@ import com.alibaba.druid.filter.wall.IllegalSQLObjectViolation;
import com.alibaba.druid.filter.wall.WallVisitor;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLNotExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
@@ -108,7 +112,7 @@ public class WallVisitorUtils {
if (x.getLeft() instanceof SQLNullExpr && x.getRight() instanceof SQLNullExpr) {
return false;
}
if (leftResult == null || rightResult == null) {
return null;
}
@@ -151,7 +155,7 @@ public class WallVisitorUtils {
return null;
}
public static Object getValue(SQLExpr x) {
if (x instanceof SQLBinaryOpExpr) {
return getValue((SQLBinaryOpExpr) x);
@@ -164,11 +168,11 @@ public class WallVisitorUtils {
if (x instanceof SQLNumericLiteralExpr) {
return ((SQLNumericLiteralExpr) x).getNumber();
}
if (x instanceof SQLCharExpr) {
return ((SQLCharExpr) x).getText();
}
if (x instanceof SQLNCharExpr) {
return ((SQLNCharExpr) x).getText();
}
@@ -226,7 +230,7 @@ public class WallVisitorUtils {
SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query;
boolean allawTrueWhere = false;
if (queryBlock.getWhere() == null) {
allawTrueWhere = true;
} else {
@@ -254,4 +258,77 @@ public class WallVisitorUtils {
return false;
}
public static void check(WallVisitor visitor, SQLMethodInvokeExpr x) {
String methodName = x.getMethodName();
if (visitor.getPermitFunctions().contains(methodName.toLowerCase())) {
visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x)));
}
}
public static void check(WallVisitor visitor, SQLExprTableSource x) {
SQLExpr expr = x.getExpr();
String tableName = null;
if (expr instanceof SQLPropertyExpr) {
SQLPropertyExpr propExpr = (SQLPropertyExpr) expr;
if (propExpr.getOwner() instanceof SQLIdentifierExpr) {
String ownerName = ((SQLIdentifierExpr) propExpr.getOwner()).getName();
if (visitor.getPermitSchemas().contains(ownerName.toLowerCase())) {
visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x)));
}
}
tableName = propExpr.getName();
}
if (expr instanceof SQLIdentifierExpr) {
tableName = ((SQLIdentifierExpr) expr).getName();
}
if (tableName != null) {
tableName = form(tableName);
if (visitor.getPermitTables().contains(tableName)) {
visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x)));
}
}
}
public static boolean queryBlockFromIsNull(SQLSelectQuery query) {
if (query instanceof SQLSelectQueryBlock) {
SQLTableSource from = ((SQLSelectQueryBlock) query).getFrom();
if (from == null) {
return true;
}
if (from instanceof SQLExprTableSource) {
SQLExpr fromExpr = ((SQLExprTableSource) from).getExpr();
if (fromExpr instanceof SQLName) {
String name = fromExpr.toString();
name = form(name);
if (name.equalsIgnoreCase("DUAL")) {
return true;
}
}
}
}
return false;
}
public static String form(String name) {
if (name.startsWith("\"") && name.endsWith("\"")) {
name = name.substring(1, name.length() - 1);
}
name = name.toLowerCase();
return name;
}
}
@@ -353,7 +353,7 @@ public final class JdbcUtils {
}
}
public static String read(Reader reader) {
try {
final int DEFAULT_BUFFER_SIZE = 1024 * 4;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,16 @@
package com.alibaba.druid.bvt.filter.wall;
import junit.framework.TestCase;
import org.junit.Assert;
import com.alibaba.druid.filter.wall.WallUtils;
public class OracleWallTest extends TestCase {
public void testWall() throws Exception {
Assert.assertFalse(WallUtils.isValidateOracle("select f1, f2 from t union select 1, 2"));
Assert.assertFalse(WallUtils.isValidateOracle("select * from TAB"));
}
}
@@ -33,7 +33,7 @@ public class OnlineOracleTest3 extends TestCase {
}
public void test_connect() throws Exception {
execute("select * from session_roles");
executeQuery("select * from TAB");
}
public void executeQuery(String sql) throws SQLException {