java.lang.IllegalStateException: 不允许修改锁定的参数映射

问题描述:

这个问题是在我写javaweb项目,做敏感词过滤时出现的

需求是:如果是由 getParameter(String s) 得到的数据,可以直接修改value值,将含有敏感词的部分替换为 ***

request.getParameterMap() 方法返回一个包含 HTTP 请求参数的不可修改的映射。

这样设计的主要原因是为了保护请求参数的安全性和请求的一致性。HTTP 请求参数在发送到服务器端之前已经被解析和存储起来,以供服务器端使用。如果允许修改参数值,可能会导致以下问题:

  1. 安全性问题:允许直接修改请求参数可能会导致恶意用户进行参数篡改和数据注入攻击,从而危害系统安全。

  2. 请求一致性问题:由于请求参数在多个地方会被使用,如果允许修改参数值,可能会造成请求的不一致性,导致系统无法准确处理请求。

因此,为了保持请求参数的完整性和安全性,request.getParameterMap() 方法返回的映射是不可修改的。

错误代码:

java 复制代码
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

java 复制代码
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;
                }

完整的代码:

java 复制代码
@WebFilter("/*")
public class SensitiveVocabularyFilter implements Filter {
    private final ArrayList<String> vocabularyList = new ArrayList<String>();

    @Override
    public 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);
    }


    @Override
    public 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() {

            @Override
            public 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一个新的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;
                }

                //判断方法名是否是 getParameterValue
                if (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);
    }

    @Override
    public void destroy()
    {

    }
}
相关推荐
起名字真南几秒前
【OJ题解】C++实现字符串大数相乘:无BigInteger库的字符串乘积解决方案
开发语言·c++·leetcode
爬山算法6 分钟前
Maven(28)如何使用Maven进行依赖解析?
java·maven
tyler_download12 分钟前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
小小小~12 分钟前
qt5将程序打包并使用
开发语言·qt
hlsd#13 分钟前
go mod 依赖管理
开发语言·后端·golang
小春学渗透14 分钟前
Day107:代码审计-PHP模型开发篇&MVC层&RCE执行&文件对比法&1day分析&0day验证
开发语言·安全·web安全·php·mvc
杜杜的man17 分钟前
【go从零单排】迭代器(Iterators)
开发语言·算法·golang
亦世凡华、17 分钟前
【启程Golang之旅】从零开始构建可扩展的微服务架构
开发语言·经验分享·后端·golang
2401_8574396930 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧66631 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节