最近項目部署的時候客戶使用的綠盟掃描出一些漏洞,老大讓我處理,經過看大神的博客等方式,分享一些簡單的解決方法。
一 跨網站腳本
跨網站腳本(Cross-site scripting,通常簡稱為XSS或跨站腳本或跨站腳本攻擊)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及用戶端腳本語言。
XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令代碼到網頁,使用戶加載並執行攻擊者惡意制造的網頁程序。這些惡意網頁程序通常是JavaScript,但實際上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻擊成功后,攻擊者可能得到包括但不限於更高的權限(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。 防止XSS攻擊簡單的預防就是對Request請求中的一些參數去掉一些比較敏感的腳本命令。
二 解決方案
方式一:【使用Nginx的修復方案】
server {
listen 8888 default;
server_name _;
location / {
return 403;
}
}
添加一個默認 server,當 host 頭被修改匹配不到 server 時會跳到該默認 server,該默認 server 直接返回 403 錯誤。
重啟 nginx 即可。
除了這種做法,也可以在目標 server 添加檢測規則。比如下面的 if 判斷配置。
server {
server_name 192.168.0.171;
listen 8888;
if ($http_Host !~*^192.168.0.171:8888$){
return 403;
}
include /etc/nginx/default.d/*.conf;
location / {
root /www/dvwa;
index index.php index.html index.htm;
}
}
方式二:【基於tocmat的修復方案】
經測試,最低支持Tomcat6.0.x以上版本的修復。
打開tomcat的conf目錄中的server.xml文件,將Host節點做如下配置:
<Host name="www.baidu.com" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"><!--本機對外域名--> <Alias>172.19.43.28</Alias><!--本機所支持的所有IP--> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" resolveHosts="false" pattern="%a %A %b %B %h %H %l %m %p %s %S %t %u %U %v %D %T" />
說白了,這個漏洞是因為你使用了 Host 而沒驗證它。
String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
方式三:【基於Filter的修復方案】
在工程的web.xml中配置下面代碼中的攔截器,注意該攔截器一定要放在第一個執行。
最低支持Tomcat7.0.x以上版本的修復
1、首先配置web.xml,添加如下配置信息:
<!-- xSS跨站漏洞filter --> <filter> <filter-name>xSSFilter</filter-name> <filter-class>com.founder.mrp.web.filter.XSSFilter</filter-class> </filter> <filter-mapping> <filter-name>xSSFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、編寫過濾器:
package com.founder.mrp.web.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; public class XSSFilter implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //自定義request包裝類,並把它傳入過濾器鏈 XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest)request); chain.doFilter(xssRequest , response); } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
3、包裝類
主要是覆蓋實現了getParameter,getParameterValues,getHeader這幾個方法,然后對獲取的value值進行XSS處理。
package com.founder.mrp.web.filter; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { HttpServletRequest orgRequest = null; public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); orgRequest = request; } /** * 覆蓋getParameter方法,將參數名和參數值都做xss & sql過濾。<br/> * 如果需要獲得原始的值,則通過super.getParameterValues(name)來獲取<br/> * getParameterNames,getParameterValues和getParameterMap也可能需要覆蓋 */ @Override public String getParameter(String name) { String value = super.getParameter(xssEncode(name)); if (value != null) { value = xssEncode(value); } return value; } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(xssEncode(name)); if(values != null && values.length > 0){ for(int i =0; i< values.length ;i++){ values[i] = xssEncode(values[i]); } } return values; } /** * 覆蓋getHeader方法,將參數名和參數值都做xss & sql過濾。<br/> * 如果需要獲得原始的值,則通過super.getHeaders(name)來獲取<br/> * getHeaderNames 也可能需要覆蓋 */ @Override public String getHeader(String name) { String value = super.getHeader(xssEncode(name)); if (value != null) { value = xssEncode(value); } return value; } /** * 將容易引起xss & sql漏洞的半角字符直接替換成全角字符 * * @param s * @return */ private static String xssEncode(String s) { if (s == null || s.isEmpty()) { return s; }else{ s = stripXSSAndSql(s); } StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '(': sb.append("("); break; case ')': sb.append(")"); break; case '&': sb.append("&"); break; case '|': sb.append("|"); break; case '+': sb.append("+"); break; case '%': sb.append("%"); break; case '@': sb.append("@"); break; 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(); } /** * 獲取最原始的request * * @return */ public HttpServletRequest getOrgRequest() { return orgRequest; } /** * 獲取最原始的request的靜態方法 * * @return */ public static HttpServletRequest getOrgRequest(HttpServletRequest req) { if (req instanceof XssHttpServletRequestWrapper) { return ((XssHttpServletRequestWrapper) req).getOrgRequest(); } return req; } /** * * 防止xss跨腳本攻擊(替換,根據實際情況調整) */ public static String stripXSSAndSql(String value) { if (value != null) { // NOTE: It's highly recommended to use the ESAPI library and // uncomment the following line to // avoid encoded attacks. // value = ESAPI.encoder().canonicalize(value); // Avoid null characters value = value.replaceAll("", ""); // Avoid anything between script tags Pattern scriptPattern = Pattern.compile("<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid anything in a src="..." type of e-xpression scriptPattern = Pattern.compile("src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome </script> tag scriptPattern = Pattern.compile("</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome <script ...> tag scriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid eval(...) expressions scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid e-xpression(...) expressions scriptPattern = Pattern.compile("e-xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Avoid javascript:... expressions scriptPattern = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid vbscript:... expressions scriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid onload= expressions scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome <script ...> tag scriptPattern = Pattern.compile("<iframe>(.*?)</iframe>",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("</iframe>",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("<iframe(.*?)>",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); } return value; } }
由於嘗試較多,也比較混亂,也不確定哪個適用各位的情況,只能多查多參考。