URL存在跨站漏洞http host頭攻擊漏洞解決方案


最近項目部署的時候客戶使用的綠盟掃描出一些漏洞,老大讓我處理,經過看大神的博客等方式,分享一些簡單的解決方法。

一 跨網站腳本

跨網站腳本(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;
    }

}

由於嘗試較多,也比較混亂,也不確定哪個適用各位的情況,只能多查多參考。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM