0x01、XSS漏洞
總所周知,xss分為三類,反射型,存儲型xss,dom型xss。那xss還能有不一樣嗎?不,都一樣。php中的xss
那么我們就不細細講解了,畢竟大家看的懂php,那么java和php的漏洞原理都是一致的
0x02、反射型xss
<%=request.getParameter("id")%>
就這么短短一句話,也就是說,用戶輸入的參數沒有進行過濾,就會進行反射型xss
0x02、存儲型xss
test.jsp 代碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.*" %>
<%
String username = request.getParameter("username");
String content = request.getParameter("content");
String guestBookKey = "GUEST_BOOK";
List<Map<String, String>> comments = new ArrayList<Map<String, String>>();
if (content != null) {
Object obj = application.getAttribute(guestBookKey);
if (obj != null) {
comments = (List<Map<String, String>>) obj;
}
Map<String, String> comment = new HashMap<String, String>();
String ip = request.getHeader("x-real-ip");
if (ip == null) {
ip = request.getRemoteAddr();
}
comment.put("username", username);
comment.put("content", content);
comment.put("ip", ip);
comment.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
comments.add(comment);
application.setAttribute(guestBookKey, comments);
}
%>
<html>
<head>
<title>留言板</title>
</head>
<style>
* {
margin: 0;
padding: 0;
}
</style>
<body>
<div style="border: 1px solid #C6C6C6;">
<div style="text-align: center;">
<h2>在線留言板</h2>
</div>
<div>
<dl>
<%
Object obj = application.getAttribute(guestBookKey);
if (obj instanceof List) {
comments = (List<Map<String, String>>) obj;
for (Map<String, String> comment : comments) {
%>
<dd>
<div style="min-height: 50px; margin: 20px; border-bottom: 1px solid #9F9F9F;">
<p><B><%=comment.get("username")%>
</B>[<%=comment.get("ip")%>] 於 <%=comment.get("date")%> 發表回復:</p>
<p style="margin: 15px 0 5px 0; font-size: 12px;">
<pre><%=comment.get("content")%></pre>
</p>
</div>
</dd>
<%
}
}
%>
</dl>
</div>
<div style="background-color: #fff; border: 1px solid #C6C6C6;">
<form action="#" method="POST" style="margin: 20px;">
昵稱: <input type="text" name="username" style="width:250px; height: 28px;"/><br/><br/>
<textarea name="content" style="overflow: auto;width: 100%; height: 250px;"></textarea>
<input type="submit" value="提交留言" style="margin-top: 20px; width: 80px; height: 30px;"/>
</form>
</div>
</div>
</body>
</html>
我們斷點慢慢走,不急,首先content是留言板的內容,然后username是昵稱。這邊判斷留言板內容不為空;然后走了進去,獲取域對象的這個guestBookKey的值。然后再判斷是否為空
判斷為空之后繼續往下走
然后這邊繼續存到hashmap當中。comments是個ArrayList類型的,他存儲的類型是map類型,同時兩邊都是字符串;然后再四個參數為一個comments。最后再設置到域對象當中
那么話不多說都知道,最后打印出來。重點就來了,我們知道xss語句一般是插入數據庫當中,然后再讀取出來。而java,則可以存儲到數據庫,也可以存儲到域對象當中。但是當Tomcat重啟之后,數據就會重置為空。
0x03、xss防御
4.1 htmlspecialchars
在PHP中通常會使用htmlspecialchars函數會將一些可能有攻擊威脅的字符串轉義為html實體編碼,這樣可以有效的避免XSS攻擊。
示例 - htmlspecialchars 轉義:
在Java中雖然沒有內置如此簡單方便的函數,但是我們可以通過字符串替換的方式實現類似htmlspecialchars
函數的功能。
/**
* 實現htmlSpecialChars函數把一些預定義的字符轉換為HTML實體編碼
*
* @param content 輸入的字符串內容
* @return HTML實體化轉義后的字符串
*/
public static String htmlSpecialChars(String content) {
if (content == null) {
return null;
}
char[] charArray = content.toCharArray();
StringBuilder sb = new StringBuilder();
for (char c : charArray) {
switch (c) {
case '&':
sb.append("&");
break;
case '"':
sb.append(""");
break;
case '\'':
sb.append("'");
break;
case '<':
sb.append("<");
break;
case '>':
sb.append(">");
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}
在存儲或者輸出請求參數的時候使用該方法過濾即可實現XSS防御。
4.2 全局的XSSFilter
package com.anbai.sec.vuls.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
public class XSSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
// 創建HttpServletRequestWrapper,包裝原HttpServletRequest對象,示例程序只重寫了getParameter方法,
// 應當考慮如何過濾:getParameter、getParameterValues、getParameterMap、getInputStream、getReader
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
public String getParameter(String name) {
// 獲取參數值
String value = super.getParameter(name);
// 簡單轉義參數值中的特殊字符
return value.replace("&", "&").replace("<", "<").replace("'", "'");
}
};
chain.doFilter(requestWrapper, resp);
}
@Override
public void destroy() {
}
}
web.xml添加XSSFilter過濾器:
<!-- XSS過濾器 -->
<filter>
<filter-name>XSSFilter</filter-name>
<filter-class>com.anbai.sec.vuls.filter.XSSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XSSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
請求XSS示例程序:http://localhost:8000/modules/servlet/xss.jsp?input=%3Cscript%3Ealert(%27xss%27);%3C/script%3E
經過全局過濾器轉義后的參數就不會再帶有XSS攻擊能力了。
4.3 RASP XSS攻擊防御
RASP可以實現類似於全局XSSFilter的請求參數過濾功能,比較穩定的一種方式是Hook到javax.servlet.ServletRequest
接口的實現類的getParameter/getParameterValues/getParameterMap
等核心方法,在該方法return之后插入RASP的檢測代碼。這種實現方案雖然麻煩,但是可以避免觸發Http請求參數解析問題(Web應用無法獲取getInputStream
和亂碼等問題)。
示例 - RASP對getParameter返回值Hook示例:
反射型的XSS防御相對來說比較簡單,直接禁止GET參數中出現<>
標簽,只要出現就理解攔截,如:
http://localhost:8000/modules/servlet/xss.jsp?input=<script>alert('xss');</script>
過濾或攔截掉<>
后input
參數就不再具有攻擊性了。
但是POST請求的XSS參數就沒有那么容易過濾了,為了兼顧業務,不能簡單的使用htmlSpecialChars
的方式直接轉義特殊字符,因為很多時候應用程序是必須支持HTML標簽的(如:<img>、<h1>
等)。RASP在防御XSS攻擊的時候應當盡可能的保證用戶的正常業務不受影響,否則可能導致用戶無法業務流程阻塞或崩潰。
為了支持一些常用的HTML標簽和HTML標簽屬性,RASP可以通過詞法解析的方式,將傳入的字符串參數值解析成HTML片段,然后分析其中的標簽和屬性是否合法即可。
0x04、總結
我們要挖掘xss的漏洞同時,我們也需要知道它的過濾方式。比如某cms利用Filter進行過濾xss。那么我們就可以去看看filter是否存在過濾xss,如果存在的話,我們就可以快速判斷是否存在xss。不然直接白盒可能沒看到過濾點,但是就是無法彈窗。其實這也是代碼審計中,最常見的一種方式,那就是看配置文件