mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
sql wall filter
This commit is contained in:
@@ -11,22 +11,23 @@ import com.alibaba.druid.filter.wall.WallVisitor;
|
||||
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.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlExecuteStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTablesStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
|
||||
|
||||
public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisitor {
|
||||
public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisitor, MySqlASTVisitor {
|
||||
|
||||
private final Set<String> permitFunctions = new HashSet<String>();
|
||||
private final Set<String> permitTables = new HashSet<String>();
|
||||
@@ -79,29 +80,6 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
|
||||
return violations;
|
||||
}
|
||||
|
||||
public boolean visit(MySqlExecuteStatement x) {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MySqlShowTablesStatement x) {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MySqlShowDatabasesStatement x) {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MySqlShowColumnsStatement x) {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLBinaryOpExpr x) {
|
||||
WallVisitorUtils.check(this, x);
|
||||
|
||||
@@ -122,11 +100,6 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
|
||||
return visit((SQLSelectQueryBlock) x);
|
||||
}
|
||||
|
||||
public boolean visit(SQLDropTableStatement x) {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLVariantRefExpr x) {
|
||||
String varName = x.getName();
|
||||
if (varName == null) {
|
||||
@@ -183,4 +156,21 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
|
||||
return permitTables.contains(name);
|
||||
}
|
||||
|
||||
public void preVisit(SQLObject x) {
|
||||
if (!(x instanceof SQLStatement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x instanceof SQLInsertStatement) {
|
||||
|
||||
} else if (x instanceof SQLSelectStatement) {
|
||||
|
||||
} else if (x instanceof SQLDeleteStatement) {
|
||||
|
||||
} else if (x instanceof SQLUpdateStatement) {
|
||||
|
||||
} else {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
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;
|
||||
@@ -14,25 +8,27 @@ 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.SQLStatement;
|
||||
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.SQLDeleteStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
|
||||
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>();
|
||||
@@ -55,40 +51,8 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi
|
||||
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);
|
||||
}
|
||||
WallVisitorUtils.loadResource(this.permitFunctions, "META-INF/druid-filter-wall-permit-function.txt");
|
||||
WallVisitorUtils.loadResource(this.permitTables, "META-INF/druid-filter-wall-permit-table.txt");
|
||||
}
|
||||
|
||||
public void addPermitName(String name) {
|
||||
@@ -100,13 +64,12 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi
|
||||
name = name.toLowerCase();
|
||||
permitFunctions.add(name);
|
||||
}
|
||||
|
||||
|
||||
public void addPermitTable(String name) {
|
||||
name = name.toLowerCase();
|
||||
permitTables.add(name);
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getPermitNames() {
|
||||
return permitNames;
|
||||
}
|
||||
@@ -155,7 +118,7 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi
|
||||
WallVisitorUtils.check(this, x);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean visit(SQLExprTableSource x) {
|
||||
WallVisitorUtils.check(this, x);
|
||||
|
||||
@@ -165,7 +128,7 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean visit(SQLUnionQuery x) {
|
||||
if (WallVisitorUtils.queryBlockFromIsNull(x.getLeft()) || WallVisitorUtils.queryBlockFromIsNull(x.getRight())) {
|
||||
@@ -174,15 +137,35 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void preVisit(SQLObject x) {
|
||||
if (!(x instanceof SQLStatement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x instanceof SQLInsertStatement) {
|
||||
|
||||
} else if (x instanceof SQLSelectStatement) {
|
||||
|
||||
} else if (x instanceof SQLDeleteStatement) {
|
||||
|
||||
} else if (x instanceof SQLUpdateStatement) {
|
||||
} else if (x instanceof OracleMultiInsertStatement) {
|
||||
|
||||
} else if (x instanceof OracleMergeStatement) {
|
||||
} else {
|
||||
violations.add(new IllegalSQLObjectViolation(SQLUtils.toMySqlString(x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
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.Enumeration;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.druid.filter.wall.IllegalSQLObjectViolation;
|
||||
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.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
@@ -24,9 +34,12 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBooleanExpr;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
|
||||
public class WallVisitorUtils {
|
||||
|
||||
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
|
||||
|
||||
public static void check(WallVisitor visitor, SQLBinaryOpExpr x) {
|
||||
if (Boolean.TRUE == getValue(x)) {
|
||||
visitor.getViolations().add(new IllegalSQLObjectViolation(SQLUtils.toSQLString(x)));
|
||||
@@ -209,15 +222,15 @@ public class WallVisitorUtils {
|
||||
return ((String) firstValue).length();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ("if".equalsIgnoreCase(methodName) && x.getParameters().size() == 3) {
|
||||
SQLExpr first = x.getParameters().get(0);
|
||||
Object firstResult = getValue(first);
|
||||
|
||||
|
||||
if (Boolean.TRUE == firstResult) {
|
||||
return getValue(x.getParameters().get(1));
|
||||
}
|
||||
|
||||
|
||||
if (Boolean.FALSE == firstResult) {
|
||||
getValue(x.getParameters().get(2));
|
||||
}
|
||||
@@ -290,7 +303,7 @@ public class WallVisitorUtils {
|
||||
|
||||
if (propExpr.getOwner() instanceof SQLIdentifierExpr) {
|
||||
String ownerName = ((SQLIdentifierExpr) propExpr.getOwner()).getName();
|
||||
|
||||
|
||||
ownerName = form(ownerName);
|
||||
|
||||
if (visitor.getPermitSchemas().contains(ownerName.toLowerCase())) {
|
||||
@@ -345,8 +358,41 @@ public class WallVisitorUtils {
|
||||
if (name.startsWith("`") && name.endsWith("`")) {
|
||||
name = name.substring(1, name.length() - 1);
|
||||
}
|
||||
|
||||
|
||||
name = name.toLowerCase();
|
||||
return name;
|
||||
}
|
||||
|
||||
public static void loadResource(Set<String> names, String resource) {
|
||||
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) {
|
||||
line = line.toLowerCase();
|
||||
names.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
url.openStream();
|
||||
} finally {
|
||||
JdbcUtils.close(reader);
|
||||
JdbcUtils.close(in);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("load oracle permit tables errror", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.alibaba.druid.bvt.filter.wall;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.alibaba.druid.filter.wall.WallUtils;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* 这个场景测试访问MySql系统函数
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
public class MySqlWallLoadDataInfileTest extends TestCase {
|
||||
|
||||
public void test_permit_stmt() throws Exception {
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("load data infile 'c:/boot.ini' into table foo"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.alibaba.druid.bvt.filter.wall;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.alibaba.druid.filter.wall.WallUtils;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* 这个场景测试访问MySql系统表
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
public class MySqlWallPermitFunctionTest extends TestCase {
|
||||
|
||||
public void test_permitTable() throws Exception {
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM mysql.user"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM `mysql`.`user`"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM \"mysql\".\"user\""));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM MYSQL.USER"));
|
||||
}
|
||||
|
||||
public void test_permitTable_subquery() throws Exception {
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM mysql.user) a"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM `mysql`.`user`) a"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM \"mysql\".\"user\") a"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM MYSQL.USER) a"));
|
||||
}
|
||||
}
|
||||
@@ -7,23 +7,14 @@ import com.alibaba.druid.filter.wall.WallUtils;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* 这个场景测试访问MySql系统表
|
||||
* 这个场景测试访问MySql系统函数
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
public class MySqlWallPermitTableTest extends TestCase {
|
||||
|
||||
public void test_permitTable() throws Exception {
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM mysql.user"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM `mysql`.`user`"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM \"mysql\".\"user\""));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("SELECT User,Password FROM MYSQL.USER"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select benchmark( 500000, sha1( 'test' ) )"));
|
||||
}
|
||||
|
||||
public void test_permitTable_subquery() throws Exception {
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM mysql.user) a"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM `mysql`.`user`) a"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM \"mysql\".\"user\") a"));
|
||||
Assert.assertFalse(WallUtils.isValidateMySql("select * from(SELECT User,Password FROM MYSQL.USER) a"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class OnlineOracleTest3 extends TestCase {
|
||||
}
|
||||
|
||||
public void test_connect() throws Exception {
|
||||
executeQuery("select * from TAB");
|
||||
executeQuery("select * from \"SYS\".TAB");
|
||||
}
|
||||
|
||||
public void executeQuery(String sql) throws SQLException {
|
||||
|
||||
@@ -33,7 +33,7 @@ public class TestOnlineSQLTest3 extends TestCase {
|
||||
// ResultSet rs = conn.getMetaData().getTables(null, null, null, null);
|
||||
// JdbcUtils.printResultSet(rs);
|
||||
|
||||
String sql = "SELECT User,Password FROM mysql.user;";
|
||||
String sql = "select benchmark( 1, sha1( 'test' ) )";
|
||||
Statement stmt = conn.createStatement();
|
||||
|
||||
ResultSet rs = stmt.executeQuery(sql);
|
||||
|
||||
Reference in New Issue
Block a user