背景
項目上線之後使用綠盟或Acunetix安全掃描工具掃描後發現了頭攻擊漏洞。截圖如下:
漏洞提示
檢測工具在檢測出漏洞後給予的提示為:
大意為不要使用request中的serverName,也就是說host header可能會在攻擊時被篡改,依賴request的方法是不可靠的,形如JSP頭部中的:
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
1
2
這樣的使用方法就會被漏洞檢測工具查出來,認定有頭攻擊漏洞。
解決辦法
提示中說,如果是php的話不要用_SERVER[“HTTP_HOST”],apache和Nginx通過設定虛拟機來紀要非法header,而web開發中常見的運作容器就是tomcat,網絡查找出的解決方案大多不适用,最後,我們找到了一個折中的辦法。
主要解決辦法,就是在請求攔截上面做host合法性校驗,攔截掉非法請求。
public class SessionFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 頭攻擊檢測
String requestHost = request.getHeader("host");
if (requestHost != null && !ServerWhiteListUtil.isWhite(requestHost)) {
response.setStatus(403);
return;
}
...
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上述代碼是常見的web系統攔截器doFilter方法,我們在方法開始的地方做host判定,如果不在白名單内,則傳回403狀态碼。漏洞工具收到403後認為通路請求已被終止,就不會報錯了。
其中,ServerWhiteListUtil.isWhite(requestHost))方法:
package ...;
import java.io.InputStreamReader;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* 伺服器白名單清單
*/
public class ServerWhiteListUtil {
private static List<String> whiteList = null;;
static {
try {
// 讀取白名單清單
whiteList = new Gson().fromJson(
new InputStreamReader(ServerWhiteListUtil.class.getResourceAsStream("/serverWhiteList.json")),
new TypeToken<List<String>>() {
}.getType());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 判斷目前host是否在白名單内
* @param host 待查host
* @return boolean 是否在白名單内
*/
public static boolean isWhite(String host) {
if (whiteList == null || whiteList.size() == 0) {
return true;
}
for (String str : whiteList) {
if (str != null && str.equals(host)) {
return true;
}
}
return false;
}
}