【问题标题】:Handling duplicate GET requests (caused by Trendmicro) in a Tomcat servlet在 Tomcat servlet 中处理重复的 GET 请求(由 Trendmicro 引起)
【发布时间】:2023-03-21 11:48:02
【问题描述】:

在 Apache Tomcat servlet 中处理来自同一客户端的重复 GET 请求的最佳策略是什么?

基本上,我得到的是相隔几秒钟的 2 个请求,第一个来自客户端的真实 IP,第二个来自 TrendMicro 服务器(这似乎与here 描述的效果相同。

现在我的 servlet 忠实地为这两个请求提供服务,但后来产生了问题(因为它调用了另一个很可能也无法处理这种情况的远程服务)。

所以问题是,我怎样才能阻止第二个请求?或者有没有其他策略来解决这个问题?

谢谢!

【问题讨论】:

    标签: java tomcat servlets


    【解决方案1】:

    所以我刚刚发现这也会导致我的网站出现问题。我存储了客户在会话中请求的当前信息,但我收到了看似随机的情况的报告,其中用户会查看一个客户信息,去查看另一个客户信息,添加评论,但评论结束第一客户记录。

    我今天找到了罪魁祸首。它是趋势科技,在真实用户查看第二个客户信息和添加评论之间镜像对第一个客户记录的呼叫。他们还欺骗了 cookie,这是主要问题。

    即。 1) 真实 IP 呼叫客户 1 信息(信息存储在会话中)

    2) 真实 IP 呼叫客户 2 信息(信息存储在会话中,替换客户 1 信息)

    3) TrendMicro IP 呼叫客户 1 信息(信息存储在会话中,替换客户 2 信息)

    4) 真实 IP 添加评论,该评论被添加到存储在会话中的客户,现在,感谢 TrendMicro,它是客户 1。

    解决方案? - 我添加了一项检查,以确保我们只为来自登录 IP 地址的调用提供服务。

    要做到这一点,你需要做两件事。

    1) 在您的登录代码上,验证登录凭据后,使用此代码将用户 IP 地址存储在会话中:

    session.setAttribute("LoginIPAddress", request.getRemoteAddr());
    

    接下来,编写一个实现 javax.servlet.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.HttpSession;
    public class ServletUserAuthenticationFilter implements Filter {
    
    
        // ----------------------------------------------------- Instance Variables
    
    
        /**
         * The default character forwardTo to set for requests that pass through
         * this filter.
         */
        protected String forwardTo = null;
    
    
        /**
         * Take this filter out of service.
         */
        public void destroy() {
            this.forwardTo = null;
        }
    
        /**
         * Select and set (if specified) the character forwardTo to be used to
         * interpret request parameters for this request.
         *
         * @param request The servlet request we are processing
         * @param result The servlet response we are creating
         * @param chain The filter chain we are processing
         *
         * @exception IOException if an input/output error occurs
         * @exception ServletException if a servlet error occurs
         */
        public void doFilter(ServletRequest request, ServletResponse response,
                             FilterChain chain)
        throws IOException, ServletException {
    
            javax.servlet.http.HttpServletRequest httpRequest = (javax.servlet.http.HttpServletRequest)request;
            HttpSession session = httpRequest.getSession();
    
            // Is there a valid session?
            // We now also redirect requests if the remote IP Address is not the same address that originally signed in
            if(!httpRequest.getRequestURI().equals(httpRequest.getContextPath()+"/services/login") && !httpRequest.getRequestURI().equals(httpRequest.getContextPath()+"/services/logout")
                    && (((session==null || session.getAttribute("userData")==null))
                    || (session!=null && session.getAttribute("LoginIPAddress")!=null && !session.getAttribute("LoginIPAddress").equals(httpRequest.getRemoteAddr())))){
                // An Https page has been requested, but no valid session has been found, ao forward the user to the page indicated by forwardTo
                javax.servlet.http.HttpServletResponse httpResponse = (javax.servlet.http.HttpServletResponse)response;
                StringBuffer logonQuery = new StringBuffer();
                logonQuery.append(httpRequest.getScheme());
                logonQuery.append("://");
                logonQuery.append(request.getServerName());
                logonQuery.append(":");
                logonQuery.append(httpRequest.getLocalPort());
                logonQuery.append(httpRequest.getContextPath());
                logonQuery.append(forwardTo);
                session = httpRequest.getSession(true);
                session.setAttribute("MESSAGE", "Your session has expired. Please login again");
                httpResponse.sendRedirect(logonQuery.toString());
                return;
            }
    
            // Pass control on to the next filter
            chain.doFilter(request, response);
    
        }
    
    
        /**
         * Place this filter into service.
         *
         * @param filterConfig The filter configuration object
         */
        public void init(FilterConfig filterConfig) throws ServletException {
    
            this.forwardTo = filterConfig.getInitParameter("forwardTo");
        }
    
    
    }
    

    我在此代码中有一些您可能不需要的额外检查,但主要部分检查是 !session.getAttribute("LoginIPAddress").equals(httpRequest.getRemoteAddr())

    最后,您需要在每次服务器收到请求时运行此代码,方法是将其添加到您的 web.xml 中

      <filter>
        <filter-name>Check User Has Logged In</filter-name>
        <filter-class>au.com.mySystem.utils.filter.ServletUserAuthenticationFilter</filter-class>
        <init-param>
          <param-name>forwardTo</param-name>
          <param-value>/pages/loginForwarder.jsp</param-value>
        </init-param>
      </filter>
    

    我的代码现在又可以正常工作了(不用感谢 TrendMicro)

    【讨论】:

      【解决方案2】:

      如果您的 servlet 直接为请求提供服务,那么简单的 rate limiting filter 就可以解决问题 - 而不是使用这样的会话,而是将其更改为使用传入请求方法 + 路径 + ip,然后为 Trendmicro ip 创建第二个条目.

      然而,适当的网络服务器通常在这方面做得更好,所以如果你有一个(例如 nginx 或 apache),那么我会考虑在那里做,或者你可以简单地阻止趋势科技 IP 地址(如果它来自同一个 IP)

      【讨论】:

      • 好的,我想这是一种有效的方法——尽管这意味着对“攻击性”趋势科技 IP 进行硬编码。由于此服务仅由注册用户调用,因此我现在实现了一个过滤器,它使用用户的 id 在第一个(真实)请求仍在运行时阻止重复请求。
      猜你喜欢
      • 1970-01-01
      • 2019-02-28
      • 2021-12-18
      • 1970-01-01
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 2013-02-18
      • 1970-01-01
      相关资源
      最近更新 更多