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:
@@ -4,10 +4,14 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.filter.wall.Violation;
|
||||
import com.alibaba.druid.filter.wall.WallVisitor;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
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.visitor.MySqlASTVisitorAdapter;
|
||||
|
||||
public class MySqlWallVisitor extends MySqlASTVisitorAdapter {
|
||||
public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisitor {
|
||||
|
||||
private final List<Violation> violations;
|
||||
|
||||
@@ -26,4 +30,24 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter {
|
||||
public boolean visit(MySqlExecuteStatement x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLBinaryOpExpr x) {
|
||||
WallVisitorUtils.check(this, x);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SQLSelectQueryBlock x) {
|
||||
if (x.getWhere() != null) {
|
||||
x.getWhere().setParent(x);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MySqlSelectQueryBlock x) {
|
||||
return visit((SQLSelectQueryBlock) x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,29 +3,100 @@ package com.alibaba.druid.filter.wall.spi;
|
||||
import com.alibaba.druid.filter.wall.IllegalConditionViolation;
|
||||
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.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.SQLLiteralExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNotExpr;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBooleanExpr;
|
||||
|
||||
public class WallVisitorUtils {
|
||||
|
||||
public static void check(WallVisitor visitor, SQLBinaryOpExpr x) {
|
||||
if (Boolean.TRUE == getObject(x)) {
|
||||
visitor.getViolations().add(new IllegalConditionViolation(SQLUtils.toSQLString(x)));
|
||||
}
|
||||
}
|
||||
|
||||
public static Object getObject(SQLBinaryOpExpr x) {
|
||||
if (x.getLeft() instanceof SQLLiteralExpr && x.getRight() instanceof SQLLiteralExpr) {
|
||||
if (x.getOperator() == SQLBinaryOperator.Equality) {
|
||||
String leftLiteral = SQLUtils.toOracleString(x.getLeft());
|
||||
String rightLiteral = SQLUtils.toOracleString(x.getRight());
|
||||
|
||||
if (leftLiteral.equalsIgnoreCase(rightLiteral)) {
|
||||
visitor.getViolations().add(new IllegalConditionViolation(SQLUtils.toOracleString(x)));
|
||||
}
|
||||
} else if (x.getOperator() == SQLBinaryOperator.NotEqual) {
|
||||
String leftLiteral = SQLUtils.toOracleString(x.getLeft());
|
||||
String rightLiteral = SQLUtils.toOracleString(x.getRight());
|
||||
return leftLiteral.equalsIgnoreCase(rightLiteral);
|
||||
}
|
||||
|
||||
if (!leftLiteral.equalsIgnoreCase(rightLiteral)) {
|
||||
visitor.getViolations().add(new IllegalConditionViolation(SQLUtils.toOracleString(x)));
|
||||
}
|
||||
if (x.getOperator() == SQLBinaryOperator.NotEqual || x.getOperator() == SQLBinaryOperator.LessThanOrGreater) {
|
||||
String leftLiteral = SQLUtils.toSQLString(x.getLeft());
|
||||
String rightLiteral = SQLUtils.toSQLString(x.getRight());
|
||||
|
||||
return !leftLiteral.equalsIgnoreCase(rightLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
if (x.getOperator() == SQLBinaryOperator.Like) {
|
||||
if (x.getRight() instanceof SQLCharExpr) {
|
||||
String text = ((SQLCharExpr) x.getRight()).getText();
|
||||
|
||||
if (text.length() >= 0) {
|
||||
for (char ch : text.toCharArray()) {
|
||||
if (ch != '%') {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
x.getLeft().setParent(x);
|
||||
x.getRight().setParent(x);
|
||||
|
||||
if (x.getOperator() == SQLBinaryOperator.BooleanOr) {
|
||||
Object leftResult = getValue(x.getLeft());
|
||||
Object rightResult = getValue(x.getRight());
|
||||
|
||||
if (Boolean.TRUE == leftResult || Boolean.TRUE == rightResult) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (x.getOperator() == SQLBinaryOperator.BooleanAnd) {
|
||||
Object leftResult = getValue(x.getLeft());
|
||||
Object rightResult = getValue(x.getRight());
|
||||
|
||||
if (Boolean.FALSE == leftResult || Boolean.FALSE == rightResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Boolean.TRUE == leftResult && Boolean.TRUE == rightResult) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object getValue(SQLExpr x) {
|
||||
if (x instanceof SQLBinaryOpExpr) {
|
||||
return getObject((SQLBinaryOpExpr) x);
|
||||
}
|
||||
|
||||
if (x instanceof MySqlBooleanExpr) {
|
||||
return ((MySqlBooleanExpr) x).getValue();
|
||||
}
|
||||
|
||||
if (x instanceof SQLNotExpr) {
|
||||
Object result = getValue(((SQLNotExpr) x).getExpr());
|
||||
if (result != null && result instanceof Boolean) {
|
||||
return !((Boolean) result).booleanValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,32 @@ package com.alibaba.druid.sql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLObject;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlExprParser;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlLexer;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
|
||||
import com.alibaba.druid.sql.parser.ParserException;
|
||||
import com.alibaba.druid.sql.parser.SQLExprParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
|
||||
|
||||
public class SQLUtils {
|
||||
|
||||
public static String toSQLString(SQLObject sqlObject) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
sqlObject.accept(new SQLASTOutputVisitor(out));
|
||||
|
||||
String sql = out.toString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
public static String toMySqlString(SQLObject sqlObject) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
sqlObject.accept(new MySqlOutputVisitor(out));
|
||||
@@ -20,14 +35,28 @@ public class SQLUtils {
|
||||
String sql = out.toString();
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
public static SQLExpr toMySqlExpr(String sql) {
|
||||
MySqlLexer lexer = new MySqlLexer(sql);
|
||||
lexer.nextToken();
|
||||
|
||||
MySqlExprParser parser = new MySqlExprParser(lexer);
|
||||
SQLExpr expr = parser.expr();
|
||||
|
||||
if (lexer.token() != Token.EOF) {
|
||||
throw new ParserException("illegal sql expr : " + sql);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
public static String formatMySql(String sql) {
|
||||
MySqlStatementParser parser = new MySqlStatementParser(sql);
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
|
||||
|
||||
StringBuilder out = new StringBuilder();
|
||||
MySqlOutputVisitor visitor = new MySqlOutputVisitor(out);
|
||||
|
||||
|
||||
for (SQLStatement stmt : statementList) {
|
||||
stmt.accept(visitor);
|
||||
}
|
||||
@@ -40,15 +69,15 @@ public class SQLUtils {
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
|
||||
OracleOutputVisitor visitor;
|
||||
|
||||
|
||||
if (statementList.size() == 1) {
|
||||
visitor = new OracleOutputVisitor(out, false);
|
||||
} else {
|
||||
visitor = new OracleOutputVisitor(out, true);
|
||||
}
|
||||
|
||||
|
||||
for (SQLStatement stmt : statementList) {
|
||||
stmt.accept(visitor);
|
||||
}
|
||||
@@ -75,14 +104,28 @@ public class SQLUtils {
|
||||
public static String formatPGSql(String sql) {
|
||||
PGSQLStatementParser parser = new PGSQLStatementParser(sql);
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
|
||||
|
||||
StringBuilder out = new StringBuilder();
|
||||
PGOutputVisitor visitor = new PGOutputVisitor(out);
|
||||
|
||||
|
||||
for (SQLStatement stmt : statementList) {
|
||||
stmt.accept(visitor);
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static SQLExpr toSQLExpr(String sql) {
|
||||
MySqlLexer lexer = new MySqlLexer(sql);
|
||||
lexer.nextToken();
|
||||
|
||||
SQLExprParser parser = new SQLExprParser(lexer);
|
||||
SQLExpr expr = parser.expr();
|
||||
|
||||
if (lexer.token() != Token.EOF) {
|
||||
throw new ParserException("illegal sql expr : " + sql);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ public class SQLExprParser extends SQLParser {
|
||||
accept(Token.RPAREN);
|
||||
return primaryRest(sqlExpr);
|
||||
} else {
|
||||
SQLExpr restExpr = primary();
|
||||
SQLExpr restExpr = expr();
|
||||
sqlExpr = new SQLNotExpr(restExpr);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.alibaba.druid.bvt.filter.wall;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.alibaba.druid.filter.wall.spi.WallVisitorUtils;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
|
||||
public class WallVisitorUtilsTest extends TestCase {
|
||||
|
||||
public void test_isTrue() throws Exception {
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("1 != 2")));
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("1 != 2 AND 2 = 2")));
|
||||
Assert.assertEquals(Boolean.FALSE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("1 != 2 AND 2 != 2")));
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("23 = 23")));
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("NOT 23 != 23")));
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("f1 like '%'")));
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("f1 like '%%'")));
|
||||
Assert.assertEquals(null, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("a1 = b1 AND f1 like '%%'")));
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("a1 = b1 OR f1 like '%%'")));
|
||||
|
||||
Assert.assertEquals(Boolean.TRUE, WallVisitorUtils.getValue(SQLUtils.toSQLExpr("1 < 2")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user