• JAVA覆写Request过滤XSS跨站脚本攻击


    注:本文非本人原著。

    demo的地址:链接:http://pan.baidu.com/s/1miEmHMo 密码:k5ca

    如何过滤Xss跨站脚本攻击,我想,Xss跨站脚本攻击令人为之头疼。为什么呢。

    尤其是有富文本编辑器的产品。xss可能出现在http的head,不说别的,新浪多次出现。

    xss可以出现在post数据的正文。图片的url。

    于是各种Xss横行,如今Xss跨站脚本漏洞的流行程度甚至超过了当年的sql。

    那么对于JAVA语言,如何防御呢。

    笔者分享一个思路:所有的web项目,所有的参数都是request获得。

    不管是json合适xml又或者post表单数据。甚至图片、文件等等都是如此。

    那么,如果对request做个手脚。是不是就可以过滤xss了呢。

    正是如此。

    如下分享代码。网络上也有类似的过滤器,但不如笔者这份强悍。

      1 
      2 package com.blog.web.base.wrapper;
      3 
      4 import java.io.ByteArrayInputStream;
      5 import java.io.ByteArrayOutputStream;
      6 import java.io.IOException;
      7 import java.io.InputStream;
      8 import java.util.ArrayList;
      9 import java.util.Enumeration;
     10 import java.util.HashMap;
     11 import java.util.List;
     12 import java.util.Map;
     13 import java.util.regex.Pattern;
     14 
     15 import javax.servlet.ServletInputStream;
     16 import javax.servlet.http.HttpServletRequest;
     17 import javax.servlet.http.HttpServletRequestWrapper;
     18 
     19 /**
     20  * 覆写Request方法,过滤XSS恶意脚本
     21  *
     22  * @author WebSOS
     23  * @time 2015-06-09
     24  */
     25 public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
     26 
     27 	HttpServletRequest orgRequest = null;
     28 
     29 	public XssHttpServletRequestWrapper(HttpServletRequest request) {
     30 		super(request);
     31 		orgRequest = request;
     32 	}
     33 
     34 	/**
     35 	 * 覆盖getParameter方法,将参数名和参数值都做xss过滤。
     36 	 */
     37 	@Override
     38 	public String getParameter(String name) {
     39 		String value = super.getParameter(name);
     40 		if (value != null) {
     41 			value = xssEncode(value);
     42 		}
     43 		return value;
     44 	}
     45 
     46 	/**
     47 	 * 覆盖getHeader方法,将参数名和参数值都做xss过滤。 避免部分head操作引发的xss
     48 	 */
     49 	@Override
     50 	public String getHeader(String name) {
     51 
     52 		String value = super.getHeader(name);
     53 		if (value != null) {
     54 			value = xssEncode(value);
     55 		}
     56 		return value;
     57 	}
     58 
     59 	/**
     60 	 * 覆盖getHeaderNames方法,避免穷举head参数名引发的xss
     61 	 */
     62 	@Override
     63 	public Enumeration<String> getHeaderNames() {
     64 
     65 		Enumeration<String> headNames = super.getHeaderNames();
     66 		String value = null;
     67 		List<String> values = new ArrayList<String>();
     68 		while (headNames.hasMoreElements()) {
     69 			try {
     70 				value = (String) headNames.nextElement();
     71 				if (value == null) {
     72 					continue;
     73 				}
     74 				value = xssEncode(value);
     75 				values.add(value);
     76 			} catch (Exception e) {
     77 				e.printStackTrace();
     78 			}
     79 		}
     80 		if (values.isEmpty()) {
     81 			return null;
     82 		}
     83 		headNames = new XssEnumerator(0, values.size(), values);
     84 		return headNames;
     85 	}
     86 
     87 	/**
     88 	 * 覆盖getParameterNames方法,避免穷举参数名引发的xss
     89 	 */
     90 	@Override
     91 	public Enumeration<String> getParameterNames() {
     92 		Enumeration<String> paraNames = super.getParameterNames();
     93 		if (paraNames == null) {
     94 			return null;
     95 		}
     96 		String value = null;
     97 		List<String> values = new ArrayList<String>();
     98 		while (paraNames.hasMoreElements()) {
     99 			try {
    100 				value = (String) paraNames.nextElement();
    101 				if (value == null) {
    102 					continue;
    103 				}
    104 				value = xssEncode(value);
    105 				values.add(value);
    106 			} catch (Exception e) {
    107 				e.printStackTrace();
    108 			}
    109 		}
    110 		if (values.isEmpty()) {
    111 			return null;
    112 		}
    113 		paraNames = new XssEnumerator(0, values.size(), values);
    114 		return paraNames;
    115 	}
    116 
    117 	/**
    118 	 * 覆盖getParameterMap方法,避免穷举参数名或值引发的xss
    119 	 */
    120 	@Override
    121 	public Map<String, String[]> getParameterMap() {
    122 		Map<String, String[]> map = super.getParameterMap();
    123 		Map<String, String[]> paraMap = new HashMap<String, String[]>();
    124 		if (map == null) {
    125 			return null;
    126 		}
    127 		String[] values = null;
    128 		for (String key : map.keySet()) {
    129 			try {
    130 				values = map.get(key);
    131 				if (values != null) {
    132 					for (int i = 0; i < values.length; i++) {
    133 						try {
    134 							values[i] = xssEncode(values[i]);
    135 						} catch (Exception e) {
    136 							e.printStackTrace();
    137 						}
    138 					}
    139 				}
    140 				paraMap.put(xssEncode(key), values);
    141 			} catch (Exception e) {
    142 				e.printStackTrace();
    143 			}
    144 		}
    145 		return paraMap;
    146 	}
    147 
    148 	/**
    149 	 * 覆盖getInputStream方法,避免上传文件出现的xss或脚本代码
    150 	 */
    151 	@Override
    152 	public ServletInputStream getInputStream() throws IOException {
    153 		XSSServletInputStream xssServletInputStream = new XSSServletInputStream();
    154 		ServletInputStream inputStream = orgRequest.getInputStream();
    155 
    156 		ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    157 		try {
    158 			int ch;
    159 			while ((ch = inputStream.read()) != -1) {
    160 				byteStream.write(ch);
    161 			}
    162 		} finally {
    163 			inputStream.close();
    164 		}
    165 		xssServletInputStream.stream = new ByteArrayInputStream(xssEncode(
    166 				new String(byteStream.toByteArray(), "iso-8859-1")).getBytes(
    167 				"iso-8859-1"));
    168 		return xssServletInputStream;
    169 	}
    170 
    171 	/**
    172 	 * 将容易引起xss漏洞的字符清理掉
    173 	 *
    174 	 * @param s
    175 	 * @return
    176 	 */
    177 	private static String xssEncode(String value) {
    178 		if (value != null) {
    179 			/*
    180 			 * value = value.replace("<", "&lt;"); value = value.replace(">",
    181 			 * "&gt;");
    182 			 */
    183 			// 如需开启富文本请撤销以下注释
    184 
    185 			Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
    186 					Pattern.CASE_INSENSITIVE);
    187 			value = scriptPattern.matcher(value).replaceAll("");
    188 
    189 			scriptPattern = Pattern.compile("</script>",
    190 					Pattern.CASE_INSENSITIVE);
    191 			value = scriptPattern.matcher(value).replaceAll("");
    192 
    193 			scriptPattern = Pattern.compile("<img.*?on.*?=.*?>",
    194 					Pattern.CASE_INSENSITIVE);
    195 			value = scriptPattern.matcher(value).replaceAll("");
    196 
    197 			scriptPattern = Pattern.compile("<script(.*?)>",
    198 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    199 							| Pattern.DOTALL);
    200 			value = scriptPattern.matcher(value).replaceAll("");
    201 
    202 			scriptPattern = Pattern.compile("eval\((.*?)\)",
    203 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    204 							| Pattern.DOTALL);
    205 			value = scriptPattern.matcher(value).replaceAll("");
    206 
    207 			scriptPattern = Pattern.compile("e­xpression\((.*?)\)",
    208 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    209 							| Pattern.DOTALL);
    210 			value = scriptPattern.matcher(value).replaceAll("");
    211 
    212 			scriptPattern = Pattern.compile("expression\((.*?)\)",
    213 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    214 							| Pattern.DOTALL);
    215 			value = scriptPattern.matcher(value).replaceAll("");
    216 
    217 			scriptPattern = Pattern.compile("javascript:",
    218 					Pattern.CASE_INSENSITIVE);
    219 			value = scriptPattern.matcher(value).replaceAll("");
    220 
    221 			scriptPattern = Pattern.compile("vbscript:",
    222 					Pattern.CASE_INSENSITIVE);
    223 			value = scriptPattern.matcher(value).replaceAll("");
    224 
    225 			scriptPattern = Pattern.compile("onload(.*?)=",
    226 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    227 							| Pattern.DOTALL);
    228 			value = scriptPattern.matcher(value).replaceAll("");
    229 
    230 			scriptPattern = Pattern.compile("<%.*?java.*?%>", Pattern.CASE_INSENSITIVE
    231 					| Pattern.MULTILINE | Pattern.DOTALL);
    232 			value = scriptPattern.matcher(value).replaceAll("");
    233 
    234 			scriptPattern = Pattern.compile("<jsp:.*?>.*?</jsp:.*?>",
    235 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    236 							| Pattern.DOTALL);
    237 			value = scriptPattern.matcher(value).replaceAll("");
    238 
    239 			scriptPattern = Pattern.compile("<meta.*?>",
    240 					Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
    241 							| Pattern.DOTALL);
    242 			value = scriptPattern.matcher(value).replaceAll("");
    243 
    244 		}
    245 		return value;
    246 	}
    247 
    248 	/**
    249 	 * 获取最原始的request
    250 	 *
    251 	 * @return
    252 	 */
    253 	public HttpServletRequest getOrgRequest() {
    254 
    255 		return orgRequest;
    256 	}
    257 
    258 	/**
    259 	 * 获取最原始的request的静态方法
    260 	 *
    261 	 * @return
    262 	 */
    263 	public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
    264 		if (req instanceof XssHttpServletRequestWrapper) {
    265 			return ((XssHttpServletRequestWrapper) req).getOrgRequest();
    266 		}
    267 
    268 		return req;
    269 	}
    270 
    271 	private class XSSServletInputStream extends ServletInputStream {
    272 		private InputStream stream;
    273 
    274 		@Override
    275 		public int read() throws IOException {
    276 			return stream.read();
    277 		}
    278 	}
    279 
    280 	private class XssEnumerator implements Enumeration<String> {
    281 		int count; // 计数器
    282 		int length; // 存储的数组的长度
    283 		List<String> dataArray; // 存储数据数组的引用
    284 
    285 		XssEnumerator(int count, int length, List<String> dataArray) {
    286 			this.count = count;
    287 			this.length = length;
    288 			this.dataArray = dataArray;
    289 
    290 		}
    291 
    292 		public boolean hasMoreElements() {
    293 			return (count < length);
    294 		}
    295 
    296 		public String nextElement() {
    297 			return dataArray.get(count++);
    298 		}
    299 	}
    300 
    301 	public static void main(String[] args) {
    302 		Enumeration<String> paraNames = (Enumeration<String>) new ArrayList();
    303 	}
    304 }
  • 相关阅读:
    使用Redis的理由
    从输入网址到显示网页的全过程分析
    Node.js初识
    GET和POST的数据传递到底有何区别?
    第四五六周学习进度
    首尾相接整数数组中最大子数组的和
    网页版四则运算
    团队介绍及项目简介
    整数数组中最大子数组的和
    软件工程个人作业03
  • 原文地址:https://www.cnblogs.com/ios9/p/7416388.html
Copyright © 2020-2023  润新知