HttpServletRequestWrapper通过filter做XSS

XSS的具体解释这里不多说,XSS简单的防注入其实就是字符的替换和屏蔽。这就需要我们在服务器接受数据对数据进行处理。

Filter能在request到达servlet的服务方法之前拦截HttpServletRequest对象,而在服务方法转移控制后又能拦截HttpServletResponse对象。

但是不能修改HttpServletRequest对象,我们可以用HttpServletRequestWrapper包装HttpServletRequest对象通过包装实现参数的修改。

这里简单介绍下ajax的请求在由HttpServletRequestWrapper拦截时获取参数的情况。

根据Servlet规范,如果同时满足下列条件,则请求体(Entity)中的表单数据,将被填充到request的parameter集合中(request.getParameter系列方法可以读取相关数据):
1 这是一个HTTP/HTTPS请求
2 请求方法是POST(querystring无论是否POST都将被设置到parameter中)
3 请求的类型(Content-Type头)是application/x-www-form-urlencoded

4 Servlet调用了getParameter系列方法

如果上述条件没有同时满足,则相关的表单数据不会被设置进request的parameter集合中,相关的数据可以通过request.getInputStream()来访问。反之,如果上述条件均满足,相关的表单数据将不能再通过request.getInputStream()来读取。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang3.StringEscapeUtils;

import com.alibaba.fastjson.JSON;
import com.fx.urthinkerManager.utils.StringUtil;

public class XSSRequestWrapper extends  HttpServletRequestWrapper {
	private String body;
	
	//private Map<String, String[]> parameterMap; // 所有参数的Map集合
	public XSSRequestWrapper(HttpServletRequest request) {
		super(request);
		body = HttpGetBody.getBodyString(request);   
		
		//parameterMap = request.getParameterMap();
		 
	}

	@Override  
    public String getQueryString() {  
        return StringEscapeUtils.escapeHtml4(super.getQueryString());  
    }  
	
	
	@Override
	public Object getAttribute(String name) {
		return super.getAttribute(name);
	}

	@Override
    public String getHeader(String name) {
        return StringEscapeUtils.escapeHtml4(super.getHeader(name));
    }

	@Override
	public String getParameter(String name) {
		System.out.println(super.getParameter(name));
		return 	StringEscapeUtils.escapeHtml4(super.getParameter(name));
	}


	@Override  
    public String[] getParameterValues(String name) {  
        String[] values = super.getParameterValues(name);  
        if(values != null) {  
            int length = values.length;  
            String[] escapseValues = new String[length];  
            for(int i = 0; i < length; i++){  
                escapseValues[i] = StringEscapeUtils.escapeHtml4(values[i]);  
            }  
            return escapseValues;  
        }  
        return super.getParameterValues(name);  
    }
	@Override
    public ServletInputStream getInputStream() throws IOException {
        ServletInputStream inputStream = null;
        if(StringUtil.isNotEmpty(body)){
        	Map<String, Object> paramMap = JSON.parseObject(body);
        	for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
        	      paramMap.put(StringEscapeUtils.escapeHtml4(entry.getKey()),
        	    		  StringEscapeUtils.escapeHtml4(entry.getValue().toString()));
        	    }
        	body = JSON.toJSONString(paramMap);
            inputStream =  new PostServletInputStream(body);
        }
        return inputStream;
    }
	

	@Override
	public BufferedReader getReader() throws IOException {
		  String enc = getCharacterEncoding();
	        if(enc == null) enc = "UTF-8";
	        return new BufferedReader(new InputStreamReader(getInputStream()));
	}  


辅助类1:由数据流过去body参数

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import javax.servlet.ServletRequest;

public class HttpGetBody {
	/**  
     * 获取请求Body  
     * @param request  
     * @return  
     */    
    public static String getBodyString(ServletRequest request) {    
       //StringBuilder sb = new StringBuilder(); 
        StringBuffer sb = new StringBuffer();
        InputStream inputStream = null;    
        BufferedReader reader = null;    
        try {    
            inputStream = request.getInputStream();    
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));    
            String line = "";    
            while ((line = reader.readLine()) != null) {    
                sb.append(line);    
            }    
        } catch (IOException e) {    
            e.printStackTrace();    
        } finally {    
            if (inputStream != null) {    
                try {    
                    inputStream.close();    
                } catch (IOException e) {    
                    e.printStackTrace();    
                }    
            }    
            if (reader != null) {    
                try {    
                    reader.close();    
                } catch (IOException e) {    
                    e.printStackTrace();    
                }    
            }    
        }    
        return sb.toString();    
    }    

辅助类2:包装数据流,用于后续的controller 获取参数

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

import javax.servlet.ServletInputStream;

public class PostServletInputStream extends  ServletInputStream {
	  private InputStream inputStream;
	  private String body ;//解析json之后的文本
	  
	  public PostServletInputStream(String body) throws IOException {
	        this.body=body;
	        inputStream = null;
	    }
	  
	  
	  private InputStream acquireInputStream() throws IOException {
	        if(inputStream == null) {
	            inputStream = new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8")));  
	            //通过解析之后传入的文本生成inputStream以便后面control调用
	        }   

	        return inputStream;
	    }
	  
	  public void close() throws IOException {
	        try {
	            if(inputStream != null) {
	                inputStream.close();
	            }
	        }
	        catch(IOException e) {
	            throw e;
	        }
	        finally {
	            inputStream = null;
	        }
	    }
	  public boolean markSupported() {
	        return false;
	    }

	    public synchronized void mark(int i) {
	        throw new UnsupportedOperationException("mark not supported");
	    }


	    public synchronized void reset() throws IOException {
	        throw new IOException(new UnsupportedOperationException("reset not supported"));
	    }
	  
	@Override
	public int read() throws IOException {
		 return acquireInputStream().read();
    
	}

}

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;

import com.fx.urthinkerManager.XSSRequest.XSSRequestWrapper;

public class XSSpringFilter implements Filter{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		 	HttpServletRequest req = (HttpServletRequest) request;  
			
	        chain.doFilter(new XSSRequestWrapper(req), response);
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}

在web.xml配置

<filter>  
        <filter-name>XSSFilter</filter-name>  
        <filter-class>com.123.XSSpringFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>XSSFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping> 
好了,代码贴完了。 惊恐 尴尬 惊恐 尴尬我也不知道自己写了个啥。。




以下是一个基本的Java代码实现XSS过滤器的示例: ``` import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class XSSFilterRequestWrapper extends HttpServletRequestWrapper { public XSSFilterRequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); } @Override public String[] getParameterValues(String parameter) { String[] values = super.getParameterValues(parameter); if (values == null) { return null; } int count = values.length; String[] encodedValues = new String[count]; for (int i = 0; i < count; i++) { encodedValues[i] = xssClean(values[i]); } return encodedValues; } @Override public String getParameter(String parameter) { String value = super.getParameter(parameter); return xssClean(value); } @Override public String getHeader(String name) { String value = super.getHeader(name); return xssClean(value); } private String xssClean(String value) { if (value != null) { // 防止脚本注入 Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // 防止表单重定向 scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // 防止脚本注入 scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll(""); // 防止HTML标签注入 scriptPattern = Pattern.compile("<", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll("<"); scriptPattern = Pattern.compile(">", Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(">"); } return value; } } ``` 这个过滤器实现了`javax.servlet.http.HttpServletRequestWrapper`接口,重写了三个方法: - `getParameterValues`:过滤所有参数值并返回过滤后的结果数组。 - `getParameter`:过滤单个参数值并返回过滤后的结果。 - `getHeader`:过滤HTTP头部并返回过滤后的结果。 它使用正则表达式来替换所有可能的XSS攻击代码,并将结果返回给调用者。使用该过滤器可以大大提高应用程序的安全性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值