Druid內建了語義級的waf,為何我們要把waf能力整合到應用中呢?
1)流量waf還是存在各種解析差異導致的bypass,類似於該 例子
2)k8s的逐漸流行,在應用中實現waf能力能減少架構層設計負擔
缺點:
1)需要應用安全工程師不間斷配合
2)對程式碼質量較好的開發團隊會顯得多此一舉
本次使用springboot2、mysql5.7、Druid12.23
先看看輸入介面
@RequestMapping("list2")
public User getList2(String name) {
if (name == null) {
name = "dato";
}
String x = CheckSqlInjection(name);
if (x != null) {
User u = new User();
u.setName(x);
return u;
}
//@Select("select * from user where name='${name}'")
return userMapper.getUserByName3(name);
}
其中 CheckSqlInjection 內容就是呼叫Druid進行語義分析的邏輯
public static String CheckSqlInjection(String sql) {
if (sql == null || sql.length() < 6) {
return null;
}
//首先開展基礎的sql正規表示式檢查
//正規表示式檢查
//.......正則檢查開始..........
//正規表示式檢查結束
//啟動druid檢查
WallConfig config = new WallConfig("/");
MySqlWallProvider newSqlWallProvider = new MySqlWallProvider(config);
//入參型別包含無符號、單引號、雙引號
//也隱藏包含了 SELECT `id`,`uid` from x WHERE `id` LIKE '%2%' 這種like注入
List < String > quotes = Arrays.asList("", "'", "\"");
String checksql;
String re;
for (String quote: quotes) {
checksql = "select id from x where id = " + quote + sql + quote;
WallCheckResult check_quote = newSqlWallProvider.check(checksql);
re = Violation_Message(checksql, check_quote);
if (re != null) {
return re;
}
}
//order by注入的情況下進行校驗,order by情況下無單引號或雙引號
//似乎和上面的無符號情況一致,可以省略?
/*
checksql = "select id,uid from x order by " + sql;
WallCheckResult check_order_by = newSqlWallProvider.check(checksql);
re = Violation_Message(checksql, check_order_by);
if (re != null) {
return re;
}
*/
//sql的in語句也可以形成sql注入,也需要小心
checksql = "Select id,uid,pid from x where id in (" + sql + ")";
WallCheckResult check_in = newSqlWallProvider.check(checksql);
re = Violation_Message(checksql, check_in);
if (re != null) {
return re;
}
return null;
}
private static String Violation_Message(String Sql, WallCheckResult check) {
List < Violation > violations = check.getViolations();
if (!violations.isEmpty()) {
int firstViolation = violations.get(0).getErrorCode();
//1001是sql語法不正確、未知錯誤為9999,它倆應忽略掉,因為正常的使用者輸入都不可能是sql注入
//錯誤碼在druid/wall/violation/ErrorCode.java之中
if (firstViolation != 1001 && firstViolation != 9999) {
//System.out.println("sqlAtt&ck: " + violations.get(0).getMessage() + " : " + Sql + "\n---------");
return violations.get(0).getMessage();
}
}
return null;
}
透過sqlmap不斷的測試發現Druid存在bug,無法解析RLIKE注入已經提交給官方,issues地址
所以也將sqlmap中涉及到root使用者注入的敏感庫和函式都放到了黑名單之中
總結:
1)這個庫很成熟了,除了RLIKE這個bug,已經可以完全在輸入時就完成語義sql注入校驗
2)整體沒有什麼難度,可以很快就復現傳達給同事