mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
add sql wall support
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user