Java servlet session not working properly with NGi

2019-08-04 08:20发布

I have a site running Java servlet, using tomcat8.5, it's working fine : http://69.197.177.154:8080/GATE_Web/index.jsp

But the guy at the ISP is concerned about security, so he suggested we use NGinx to make it safer, therefore the same app is doing a NGinx Proxy pass through, and is running at : http://gatecybertech.net/

It is not running properly, when I clicked on the buttons, the cursor at the bottom is not moving, and I've notice the "User Count : " at the upper right of the page is increasing quickly, even when there is only one user [ me ] testing the app. I use Java session to keep track of new user sessions, it's working fine in the 1st site, but when working with NGinx, it's not behaving correctly.

Since the app is complicated, in order to quickly figure out why it's not working properly with NGinx, I simplified the app and created another servlet called Test_Servlet : http://69.197.177.154:8080/GATE_Web/Test_Servlet

As you can see, when you click on different buttons, the cursor with follow and point to the clicked button.

The same Test_Servlet running with NGinx is at : http://gatecybertech.net/Test_Servlet

With this one, the cursor won't follow the button you click on.

I suspect the config for the NGinx is not properly set, what do you think is wrong with it ?

And here is the simplified servlet.

import java.io.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import Utility.*;

public class Test_Servlet extends HttpServlet
{
  private boolean Debug=false;
  String App_Id="Test_Servlet",GATE_Title,User_Id=null,Profile="Profile",requestMethod,
         Spaces_Text="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;",Line_Breaks="<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n";

  public Test_Servlet()
  {
    super();

    GATE_Title="<Table Border=0 Cellpadding=0 Cellspacing=8>\n"+
               "  <Tr><Td Align=Center><Font Color=#3636CC Size=2>Server : [Server_Info] "+Spaces_Text+" User Count : [User_Count]</Font></Td></Tr>\n"+
               "</Table>\n";
  }

/** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
 * @param request servlet request
 * @param response servlet response
 */
  private void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException
  {
    HttpSession session=request.getSession(true);
    Session_Counter counter=(Session_Counter)session.getAttribute(Session_Counter.COUNTER); 
    int User_Count=counter.getActiveSessionNumber();

    String title="Test_Servlet",Server_Info=getServletContext().getServerInfo(),Action,Current_Id_Button,responseText,
           responseString="<!DOCTYPE html>\n"+
                          "<Html>\n"+
                          "<Head>\n"+
                          "  <Title>"+title+"</Title>\n"+
                          Get_jQuery()+
                          "  <Link rel=\"stylesheet\" type=\"text/css\" href=\"GATE_Style.css\">\n"+
                          "</Head>\n\n"+
                          "<Body BgColor=#C6DAFA>\n\n"+
                          "<Center>\n"+
                          "<P><Br><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P>\n"+
                          GATE_Title.replace("[Server_Info]",Server_Info).replace("[User_Count]",User_Count+"")+"<P><P>\n";
    LinkedHashMap<String,String> params=getQueryParameterMap(request);
    int Font_Size=20,Current_Id;

    requestMethod=request.getMethod()+"()";
      response.setContentType("text/html");
    response.setHeader("Content-Type","text/html;charset=utf-8");
      PrintWriter out=response.getWriter();
    try
    {
      User_Id=Decode_String(params.get("User_Id"));
      Action=Decode_String(params.get("Action"));
      Current_Id_Button=Decode_String(params.get("Current_Id_Button"));

      Debug=(params.get("Debug")==null?Debug:params.get("Debug").toLowerCase().equals("true"));

      if (session.getAttribute("Current_Id")==null)
      {
        Current_Id=1;
        session.setAttribute("Current_Id",Current_Id+"");          
      }
      else Current_Id=Integer.parseInt((String)session.getAttribute("Current_Id"));

      if (Action!=null && Action.equals("Get_Pointer_Table"))                       // Everytime after Current_Id change, adjust pointer table
      {
          out.print(Get_Pointer_Table(Current_Id));
//        Out(Get_Pointer_Table(Current_Id));
      }
      else if (Current_Id_Button!=null && Current_Id_Button.startsWith("Current_"))      // Current_Id Button is clicked, set Current_Id to it
      {
        Current_Id=Integer.parseInt(Current_Id_Button.substring(8));
        session.setAttribute("Current_Id",Current_Id+"");
      }
      else if (Action!=null && Action.equals("Current_Id"))                              // Everytime a symbols/token is clicked, increase Current_Id by one
      {
        responseText=Current_Id+"";
        if (Current_Id<6) Current_Id++;
        else Current_Id=1;
        session.setAttribute("Current_Id",Current_Id+"");
          out.println(responseText);
//        Out(" Current_Id = "+Current_Id);
      }
      else
      {
        responseString+=Get_Parameters(params)+"<P>\n";
        // Object does not exist or is not a file: reject with 404 error.
//        responseString+="404 (Not Found)\n";
        responseString+="<Br><P><Br><P><Br><P>\n";

        Current_Id=1;
        session.setAttribute("Current_Id",Current_Id+"");
        responseString+="<Table Border=0 Cellpadding=0 Cellspacing=0>\n"+
                        "  <Tr>\n"+
                        "    <Td>\n"+
                        "      <Table Border=0 Cellpadding=0 Cellspacing=3>\n"+
                        "        <Tr>\n"+
                        "          <Td>"+Get_Html_Button("Current_1","1",82,82,Font_Size)+"</Td>\n"+
                        "          <Td>"+Get_Html_Button("Current_2","2",82,82,Font_Size)+"</Td>\n"+
                        "          <Td>"+Get_Html_Button("Current_3","3",82,82,Font_Size)+"</Td>\n"+
                        "          <Td>"+Get_Html_Button("Current_4","4",82,82,Font_Size)+"</Td>\n"+
                        "          <Td>"+Get_Html_Button("Current_5","5",82,82,Font_Size)+"</Td>\n"+
                        "          <Td>"+Get_Html_Button("Current_6","6",82,82,Font_Size)+"</Td>\n"+
                        "        </Tr>\n"+
                        "      </Table>\n"+
                        "    </Td>\n"+
                        "  </Tr>\n"+
                        "  <Tr>\n"+
                        "    <Td>\n"+
                        Get_Pointer_Table(Current_Id)+
                        "    </Td>\n"+
                        "  </Tr>\n"+
                        "</Table>\n";
        responseString+="</div>\n";
        out.println(responseString);
//      Out(responseString);
      }
    }
    catch (Exception e)
    {
      if (!e.toString().equals("java.io.IOException: Broken pipe"))                      // When user closes a window while half way writing, gets a "Broken pipe"
      {
        responseString+="<P><Pre>"+e.toString()+"\n"+Tool_Lib_Thin.Get_Stack_Trace(e)+"</Pre>\n";
        e.printStackTrace();        
      }
    }
    finally
    {
      try
      {
//        responseBody.close();
//        if (User_Id!=null && User_Id.equals("Stop_Server")) server.stop(0);
      }
      catch (Exception ex)
      {
        if (!ex.toString().equals("java.io.IOException: Broken pipe"))                   // When user closes a window while half way writing, gets a "Broken pipe"
        {
          ex.printStackTrace();
        }
      }
    }
  }

  public static String Decode_String(String Input)                                       // Fix this problem : // Error : java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "</"
  {
    if (Input==null) return null;                                                        // Replace "+" with "<plus>", and replace "%" with "<percentage>" won't work. Because characters that get encoded have % and + signs in them, 
                                                                                         // so although this helps with % and + characters in a string, yet it doesn't decode things like %20 (space) because you are taking out the percent before decoding.
    String Output="";                                                                    // Stack overflow solution : https://stackoverflow.com/questions/6067673/urldecoder-illegal-hex-characters-in-escape-pattern-for-input-string
    try                                                                                  // A solution is to replace %2B (+) and %25 (%) instead.
    {
      Output=Input.replaceAll("%(?![0-9a-fA-F]{2})","%25");                              // The first replaceAll is the regex that replaces any percent sign that isn't another encoded character with the percent encoded value. The question
      Output=Output.replaceAll("\\+","%2B");                                             // mark makes the proceeding optional, the [0-9a-fA-F] looks for those ranges of characters/numbers and the {2} looks for exactly 2 characters/numbers.
      Output=Output.replaceAll("&amp;","&");                                             // The second replaceAll just replaces the + sign with its encoded value.
      Output=URLDecoder.decode(Output,"utf-8");
    }
    catch (Exception e) { e.printStackTrace(); }
    return Output;
  }

  public LinkedHashMap<String,String> getQueryParameterMap(HttpServletRequest request)
  {
    LinkedHashMap<String,String> queryParameterMap=new LinkedHashMap();
    Map params=request.getParameterMap();
    Iterator i=params.keySet().iterator();
    while (i.hasNext())
    {
      String key=(String)i.next();
      String value=((String[])params.get(key))[0];
      queryParameterMap.put(key,value);
    }
    return queryParameterMap;
  }

  String Get_jQuery()
  {
    return "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js\"></script>\n"+
           "<script>\n"+
           "$(document).ready(function()\n"+
           "{\n"+
           "  $('button').not('#Save').not('#Login').click($.now(),function(event)\n"+                       // 100% Firefox , IE & Chrome [ OK when click on side if var Clicked_Button=event.target ]
           "   {\n"+
           "     if($(this).attr('id').indexOf('Current_')==0)       // Clicked on Current_Id_Button \n"+
           "     {\n"+
           "       $.get('Test_Servlet?Current_Id_Button='+this.id+'&now='+$.now(),function()\n"+            // use now=$.now() to avoid IE cashing
           "       {\n"+
           "         $.get('Test_Servlet?Action=Get_Pointer_Table&now='+$.now(),function(data)\n"+           // data holds new Pointer_Table html, use now=$.now() to avoid IE cashing
           "         {\n"+                                                                                   // Get_Pointer_Table must be done here after Current_Id_Button to avoid out of sync
           "           var Current_Pointer_Table=data;\n"+
           "           $(\"div.Table\").replaceWith(Current_Pointer_Table);\n"+
           "         });\n"+
           "       });\n"+
           "     }\n"+
//      " alert(data);\n"+
           "   });\n"+
           "});\n"+
           "</script>\n";
  }

  String Get_Pointer_Table(int Id)
  {
    String Pointer_Text="<Font size=4 Color=blue>\u2191</Font><Br><Font size=2 Color=blue>Current</Font>";
    return "    <div class=\"inner Table\">\n"+
           "    <Table border=0>\n"+
           "      <Tr>\n"+
           "        <Td Align=Center Width=82>"+(Id==1?Pointer_Text:"")+"</Td>\n"+
           "        <Td Align=Center Width=82>"+(Id==2?Pointer_Text:"")+"</Td>\n"+
           "        <Td Align=Center Width=82>"+(Id==3?Pointer_Text:"")+"</Td>\n"+
           "        <Td Align=Center Width=82>"+(Id==4?Pointer_Text:"")+"</Td>\n"+
           "        <Td Align=Center Width=82>"+(Id==5?Pointer_Text:"")+"</Td>\n"+
           "        <Td Align=Center Width=82>"+(Id==6?Pointer_Text:"")+"</Td>\n"+
           "        <Td Width=56>&nbsp;</Td>\n"+
           "      </Tr>\n"+
           "    </Table>\n"+
           "    </div>\n";
  }

  String Get_Html_Button(String Id,String Text,int W,int H,int Font_Size)
  {
    return "<button id="+Id+" type=button style=\""+(W<50?"padding: .01em;":"")+"width:"+W+"px;height:"+H+"px;font-size: "+Font_Size+"px\">"+Text+"</button>";
  }

  String Get_Parameters(Map<String,String> params)
  {
    String title="Reading All Request Parameters",paramName,paramValue="";
    String Parameters_Table="<Table Border=1 Align=Center Cellpadding=5 Cellspacing=2>\n  <Tr Bgcolor=#0088FF Colspan=2><Th><Font Color=White>"+title+"</Font></Th></Tr>\n</Table>\n<P>\n"+
                              "<Font Color=blue>This is class [ "+this.getClass().getName()+" ] using the "+requestMethod+" method [ "+new Date()+" ]</Font><P>\n\n"+
                            "<Table Border=1 Align=Center Cellpadding=2 Cellspacing=2>\n  <Tr Bgcolor=#99CCFF><Th>Parameter Name</Th><Th>Parameter Value(s)</Th></Tr>\n";

    for (Map.Entry<String,String> entry : params.entrySet())
    {
      paramName=entry.getKey().replace("+"," ");
      Parameters_Table+="  <Tr><Td Align=Right>"+(paramName.trim().length()<1?"&nbsp;":paramName)+"</Td>";
      try { paramValue=URLDecoder.decode(entry.getValue(),"utf-8"); }
      catch (Exception e) { e.printStackTrace(); }
// Out(paramName+" : "+paramValue);

      Parameters_Table+="<Td>"+(paramValue.trim().length()<1?"&nbsp;":paramValue)+"</Td></Tr>\n";
    }
    Parameters_Table+="</Table>\n";

    return Debug?Parameters_Table:"";
  }

  public LinkedHashMap<String,String> queryToMap(String query)                           // http://localhost:6600/Resume_App?Id=Edit&File_Name=AT&T.txt
  {
//    Out("query = "+query);
    LinkedHashMap<String,String> result=new LinkedHashMap();
    for (String param : query.split("&"))
    {
      String pair[]=param.split("=");
      if (pair.length>1) result.put(pair[0],pair[1]);
      else result.put(pair[0],"");
    }
    return result;
  }

  private static void out(String message)
  {
    System.out.print(message);
    try { System.out.print(message); }
    catch (Exception e) { }
//    GATE_App.Log_TextArea.append(message);
  }

  private static void Out(String message)
  {
    System.out.println(message);
    try { System.out.println(message); }
    catch (Exception e) { }
//    GATE_App.Log_TextArea.append(message+"\n");
  }

  /** Handles the HTTP <code>GET</code> method. This method is called when a form has its tag value method equals to get.
   * @param request servlet request
   * @param response servlet response
   */
  public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { processRequest(request,response); }

  /** Handles the HTTP <code>POST</code> method. This method is called when a form has its tag value method equals to post.
   * @param request servlet request
   * @param response servlet response
   */
  public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { processRequest(request,response); }

  /** This method is called when a HTTP put request is received.
   * 
   * @param request the request send by the client to the server
   * @param response the response send by the server to the client
   */
  public void doPut(HttpServletRequest request, HttpServletResponse response)   throws ServletException,IOException
  {
        // Put your code here
  }

  /** This method is called when a HTTP delete request is received.
   * 
   * @param request the request send by the client to the server
   * @param response the response send by the server to the client
   */
  public void doDelete(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
  {
        // Put your code here
  }

  public void destroy() { super.destroy(); }

  /**
   * Returns information about the servlet, such as 
   * author, version, and copyright. 
   *
   * @return String information about this servlet
   */
  public String getServletInfo() { return "This is servlet : [ "+this.getClass().getName()+" ]"; }

  /**
   * Initialization of the servlet. <br>
   *
   * @throws ServletException if an error occurs
   */
  public void init() throws ServletException
  {
        // Put your code here
  }
}

=========================================================

package Utility;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.ArrayList;

public class Session_Counter implements HttpSessionListener
{
  private List<String> sessions=new ArrayList<>();
  public static final String COUNTER="session-counter";
  GATE_4_App_Lib GATE_4_app_lib=new GATE_4_App_Lib();

  public void sessionCreated(HttpSessionEvent event)
  {
    System.out.println("Session_Counter.sessionCreated");
    HttpSession session=event.getSession();
    sessions.add(session.getId());
    session.setAttribute(Session_Counter.COUNTER,this);
  }

  public void sessionDestroyed(HttpSessionEvent event)
  {
    System.out.println("Session_Counter.sessionDestroyed");
    HttpSession session=event.getSession();
    sessions.remove(session.getId());
    session.setAttribute(Session_Counter.COUNTER,this);
    GATE_4_app_lib.Save_To_GATE_Web_Log("[-] Client_IP = "+session.getAttribute("Client_IP")+", Client_Browser = "+session.getAttribute("Client_Browser"));
  }

  public int getActiveSessionNumber() { return sessions.size(); }
}

2条回答
不美不萌又怎样
2楼-- · 2019-08-04 08:42

Yes, it seems that nginx configuration is not correct

curl -vvv http://gatecybertech.net/Test_Servlet

<skip>
Set-Cookie: JSESSIONID=E3551B683A0FD1A8A17829022A070AE2;path=/GATE_Web;HttpOnly

Your site sets cookie with path /GATE_Web while from the point of a browser the URL is not under this path, so the browser will not send the cookie on subsequent requests, and HTTP session will be started over.

One suggestion is to map to /GATE_Web in nginx as well and use http://gatecybertech.net/GATE_Web/Test_Servlet instead of http://gatecybertech.net/Test_Servlet

查看更多
够拽才男人
3楼-- · 2019-08-04 08:47

Alright, I've solved the problem. By doing the following :

In /opt/tomcat85/conf/context.xml, change "<Context>" to :

<Context sessionCookiePath="/">
...
</Context>
查看更多
登录 后发表回答