问题描述:
这个问题是在我写javaweb项目,做敏感词过滤时出现的
需求是:如果是由 getParameter(String s) 得到的数据,可以直接修改value值,将含有敏感词的部分替换为 ***
request.getParameterMap()
方法返回一个包含 HTTP 请求参数的不可修改的映射。
这样设计的主要原因是为了保护请求参数的安全性和请求的一致性。HTTP 请求参数在发送到服务器端之前已经被解析和存储起来,以供服务器端使用。如果允许修改参数值,可能会导致以下问题:
安全性问题:允许直接修改请求参数可能会导致恶意用户进行参数篡改和数据注入攻击,从而危害系统安全。
请求一致性问题:由于请求参数在多个地方会被使用,如果允许修改参数值,可能会造成请求的不一致性,导致系统无法准确处理请求。
因此,为了保持请求参数的完整性和安全性,
request.getParameterMap()
方法返回的映射是不可修改的。
错误代码:
if (method.getName().equals("getParameterMap")){Map map = (Map) method.invoke(servletRequest, args);//通过getParameterMap获取到的map是不允许修改的if (map != null){Set set = map.keySet();for (Object o : set){String key = (String) o;String[] value = (String[]) map.get(key);//增强for一般不用来增加和删除for (String s : vocabularyList){if (value[0].contains(s)){
// value[0] = value[0].replaceAll(s, "***");//这里内容没有修改,原因应该也是不允许修改参数映射value[0] = "***";map.put(key, value);//这里java.lang.IllegalStateException: 不允许修改锁定的参数映射}return map;}}}}
解决方案是:用HashMap(Map m),重新new一个map,在新的map中修改值,并返回新的map
if (method.getName().equals("getParameterMap")){Map old = (Map) method.invoke(servletRequest, args);//增强返回值Map<String, String[]> values = new HashMap(old); //获取返回值if (!values.isEmpty()){for (String key : values.keySet()){String[] value = values.get(key);for (String str : vocabularyList){if (value[0].contains(str)){ //只取String[]的第一个值value[0] = value[0].replaceAll(str, "***");values.put(key, value);}}}}return values;}
完整的代码:
@WebFilter("/*")
public class SensitiveVocabularyFilter implements Filter {private final ArrayList<String> vocabularyList = new ArrayList<String>();@Overridepublic void init(FilterConfig filterConfig) throws ServletException{BufferedReader br = null;try{//获取txt的文件位置String realPath = filterConfig.getServletContext().getRealPath("/WEB-INF/classes/敏感词汇.txt");//读取文件br = new BufferedReader(new FileReader(realPath));//将读取的每一行数据添加到vocabularyList中String line = null;while ((line = br.readLine()) != null){vocabularyList.add(line);}}catch (Exception e){e.printStackTrace();}finally{try{assert br != null;br.close();}catch (IOException e){e.printStackTrace();}}System.out.println(vocabularyList);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException{//1.创建代理对象,增强getParameter方法ServletRequest proxy_request = (ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable{//执行处理逻辑,增强Parameter方法if (method.getName().equals("getParameter")){//如果我取到的参数值和敏感词汇中的相同,则需要将这个值改为***String value = (String) method.invoke(servletRequest, args);//如果获取的参数不为空if (value != null){for (String vocabulary : vocabularyList){if (value.contains(vocabulary)){value = value.replaceAll(vocabulary, "***");}}return value;}}//判断方法名是否是 getParameterMap/* if (method.getName().equals("getParameterMap")){Map map = (Map) method.invoke(servletRequest, args);//通过getParameterMap获取到的map是不允许修改的if (map != null){Set set = map.keySet();for (Object o : set){String key = (String) o;String[] value = (String[]) map.get(key);//增强for一般不用来增加和删除for (String s : vocabularyList){if (value[0].contains(s)){value[0] = value[0].replaceAll(s, "***");//java.lang.IllegalStateException: 不允许修改锁定的参数映射
// value[0] = "***";map.put(key, value);//这里java.lang.IllegalStateException: 不允许修改锁定的参数映射}return map;}}}}*///判断方法名是否是 getParameterMap//解决:new一个新的mapif (method.getName().equals("getParameterMap")){Map old = (Map) method.invoke(servletRequest, args);//增强返回值Map<String, String[]> values = new HashMap(old); //获取返回值if (!values.isEmpty()){for (String key : values.keySet()){String[] value = values.get(key);for (String str : vocabularyList){if (value[0].contains(str)){ //只取String[]的第一个值value[0] = value[0].replaceAll(str, "***");values.put(key, value);}}}}return values;}//判断方法名是否是 getParameterValueif (method.getName().equals("getParameterValues")){String[] value = (String[]) method.invoke(servletRequest, args);//需要把敏感词汇txt每一行的字符都搞到一个字符串数组中if (value != null){for (String str : vocabularyList){for (int i = 0; i < value.length; i++){if (value[i].contains(str)){value[i].replaceAll(str, "***");}}}}return value;}return method.invoke(servletRequest, args);}});//2.放行filterChain.doFilter(proxy_request, servletResponse);}@Overridepublic void destroy(){}
}