Merge pull request #636 from yakolee/master

improve sqlwall
This commit is contained in:
Yako
2014-09-01 20:50:31 +08:00
5 changed files with 128 additions and 98 deletions
@@ -41,6 +41,7 @@ public class WallConfig implements WallConfigMBean {
private boolean alterTableAllow = true;
private boolean renameTableAllow = true;
private boolean hintAllow = true;
private boolean lockTableAllow = true;
private boolean conditionAndAlwayTrueAllow = false;
private boolean conditionAndAlwayFalseAllow = false;
@@ -752,4 +753,12 @@ public class WallConfig implements WallConfigMBean {
this.inited = inited;
}
public boolean isLockTableAllow() {
return lockTableAllow;
}
public void setLockTableAllow(boolean lockTableAllow) {
this.lockTableAllow = lockTableAllow;
}
}
@@ -445,87 +445,7 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
@Override
public boolean visit(SQLCommentHint x) {
if(!provider.getConfig().isHintAllow()) {
addViolation(new IllegalSQLObjectViolation(ErrorCode.EVIL_HINTS, "hint not allow", SQLUtils.toMySqlString(x)));
return true;
}
String text = x.getText();
text = text.trim();
if (text.startsWith("!")) {
text = text.substring(1);
}
if (text.length() == 0) {
return true;
}
if (Character.isDigit(text.charAt(0))) {
addViolation(new IllegalSQLObjectViolation(ErrorCode.EVIL_HINTS, "evil hints", SQLUtils.toMySqlString(x)));
}
text = text.toLowerCase();
for (int i = 0; i < text.length(); ++i) {
char ch = text.charAt(i);
switch (ch) {
case ';':
case '>':
case '=':
case '<':
case '&':
case '|':
case '^':
case '\n':
case '.':
case '(':
addViolation(new IllegalSQLObjectViolation(ErrorCode.EVIL_HINTS, "evil hints",
SQLUtils.toMySqlString(x)));
default:
break;
}
}
if (text.indexOf("or") != -1 //
|| text.indexOf("and") != -1 //
|| text.indexOf("union") != -1 //
|| text.indexOf("xor") != -1 //
|| text.indexOf("select") != -1 //
|| text.indexOf("delete") != -1 //
|| text.indexOf("insert") != -1 //
|| text.indexOf("update") != -1 //
|| text.indexOf("into") != -1 //
|| text.indexOf("create") != -1 //
|| text.indexOf("drop") != -1 //
|| text.indexOf("alter") != -1 //
|| text.indexOf("truncate") != -1 //
|| text.indexOf("information_schema") != -1 //
|| text.indexOf("mysql") != -1 //
|| text.indexOf("performance_schema") != -1 //
|| text.indexOf("sleep") != -1 //
|| text.indexOf("benchmark") != -1 //
|| text.indexOf("load_file") != -1 //
|| text.indexOf("version") != -1 //
|| text.indexOf("database") != -1 //
|| text.indexOf("schema") != -1 //
|| text.indexOf("system_user") != -1 //
|| text.indexOf("session_user") != -1 //
|| text.indexOf("current_user") != -1 //
|| text.indexOf("user") != -1 //
|| text.indexOf("xmltype") != -1 //
|| text.indexOf("receive_message") != -1 //
|| text.indexOf("version_compile_os") != -1 //
|| text.indexOf("basedir") != -1 //
|| text.indexOf("datadir") != -1 //
) {
addViolation(new IllegalSQLObjectViolation(ErrorCode.EVIL_HINTS, "evil hints", SQLUtils.toMySqlString(x)));
}
WallVisitorUtils.check(this, x);
return true;
}
@@ -15,7 +15,22 @@
*/
package com.alibaba.druid.wall.spi;
import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.EVAL_VALUE;
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.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLCommentHint;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
@@ -84,6 +99,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlHintStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit;
@@ -92,11 +108,13 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetNamesStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowGrantsStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateSequenceStatement;
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.sqlserver.ast.stmt.SQLServerExecStatement;
import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.visitor.ExportParameterVisitor;
import com.alibaba.druid.sql.visitor.SQLEvalVisitor;
import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils;
@@ -116,25 +134,14 @@ import com.alibaba.druid.wall.WallVisitor;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
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.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.EVAL_VALUE;
public class WallVisitorUtils {
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
public final static String HAS_TRUE_LIKE = "hasTrueLike";
public final static String HAS_TRUE_LIKE = "hasTrueLike";
public final static String[] whiteHints = { "LOCAL", "TEMPORARY", "SQL_NO_CACHE", "SQL_CACHE", "HIGH_PRIORITY",
"LOW_PRIORITY", "STRAIGHT_JOIN", "SQL_BUFFER_RESULT", "SQL_BIG_RESULT", "SQL_SMALL_RESULT", "DELAYED" };
public static void check(WallVisitor visitor, SQLInListExpr x) {
@@ -2405,14 +2412,84 @@ public class WallVisitorUtils {
allow = config.isHintAllow();
denyMessage = "hint not allow";
errorCode = ErrorCode.HINT_NOT_ALLOW;
} else if (x instanceof MySqlLockTableStatement) {
allow = config.isLockTableAllow();
denyMessage = "lock table not allow";
errorCode = ErrorCode.LOCK_TABLE_NOT_ALLOW;
} else {
allow = config.isNoneBaseStatementAllow();
errorCode = ErrorCode.NONE_BASE_STATEMENT_NOT_ALLOW;
denyMessage = x.getClass() + " not allow";
}
}
if (!allow) {
addViolation(visitor, errorCode, denyMessage, x);
}
}
public static void check(WallVisitor visitor, SQLCommentHint x) {
if (!visitor.getConfig().isHintAllow()) {
addViolation(visitor, ErrorCode.EVIL_HINTS, "hint not allow", x);
return;
}
String text = x.getText();
text = text.trim();
if (text.startsWith("!")) {
text = text.substring(1);
}
if (text.length() == 0) {
return;
}
int pos = 0;
for (; pos < text.length(); pos++) {
char ch = text.charAt(pos);
if (ch >= '0' && ch <= '9') {
continue;
} else {
break;
}
}
if (pos == 5) {
text = text.substring(5);
text = text.trim();
}
text = text.toUpperCase();
boolean isWhite = false;
for (String hint : whiteHints) {
if (text.equals(hint)) {
isWhite = true;
break;
}
}
if (!isWhite) {
if (text.startsWith("FORCE INDEX") || text.startsWith("IGNORE INDEX")) {
isWhite = true;
}
}
if(!isWhite) {
if (text.startsWith("SET")) {
SQLStatementParser parser = new MySqlStatementParser(text);
List<SQLStatement> statementList = parser.parseStatementList();
if (statementList != null && statementList.size() > 0) {
SQLStatement statement = statementList.get(0);
if (statement instanceof SQLSetStatement || statement instanceof MySqlSetCharSetStatement
|| statement instanceof MySqlSetNamesStatement) {
isWhite = true;
}
}
}
}
if (!isWhite) {
addViolation(visitor, ErrorCode.EVIL_HINTS, "hint not allow", x);
}
}
}
@@ -47,6 +47,7 @@ public interface ErrorCode {
public final static int DROP_TABLE_NOT_ALLOW = 1103;
public final static int COMMENT_STATEMENT_NOT_ALLOW = 1104;
public final static int RENAME_TABLE_NOT_ALLOW = 1105;
public final static int LOCK_TABLE_NOT_ALLOW = 1105;
public final static int LIMIT_ZERO = 2200;
public final static int MULTI_STATEMENT = 2201;
@@ -53,5 +53,28 @@ public class MySqlWallTest_hint extends TestCase {
Assert.assertTrue(WallUtils.isValidateMySql(sql, config));
}
public void test_true_4() throws Exception {
WallConfig config = new WallConfig();
config.setHintAllow(true);
config.setMultiStatementAllow(true);
String sql = "LOCK TABLES `m_rpt_adgroupeffect` READ /*!32311 LOCAL */";
Assert.assertTrue(WallUtils.isValidateMySql(sql, config)); //
}
public void test_true_5() throws Exception {
WallConfig config = new WallConfig();
config.setHintAllow(true);
config.setMultiStatementAllow(true);
String sql = "DROP TABLE IF EXISTS `item_similarity`;"//
+ "\n/*!40101 SET @saved_cs_client = @@character_set_client */;"//
+ "\n/*!40101 SET character_set_client = utf8 */;" //
+ "\nCREATE TABLE `item_similarity` ("//
+ " `id` bigint(20) unsigned NOT NULL, "//
+ " `sellerId` bigint(20) DEFAULT NULL,"//
+ " PRIMARY KEY (`id`)" //
+ " ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"//
+ " \n/*!40101 SET character_set_client = @saved_cs_client */;";
Assert.assertTrue(WallUtils.isValidateMySql(sql, config)); //
}
}