1 2 Previous Next 19 Replies Latest reply on Mar 8, 2010 12:55 AM by andigit

    Session is getting merge with other session

    igain

      Hi,

      I have been using J2EE application on jboss-4.2.0.GA in a clustered mode from past 6 months and it is working perfectly.

      But in last 2-3 days I got 2 unusual reports.

      In our application there is module called Online Application which is a 3 step process

      1) 1st page captures all personal information like first name, last name address etc.

      2) When user hit continue button 2nd page comes and it display some use agreement and a check box for " I Agree" as well 4 text box
      2 of them displays firstName and lastname and both are read only text box. Other 2 to take input from for DOB and SSN.

      3) After filling out all these information when user hit submit button. All information goes to server for processing.


      No unusual behavior is on 2nd page 2 user reported that when they hit continue button on 1st page, on next page rather then displaying their name application is displaying some other name.
      And this name is another user who submitted his information in our application.

      this means session is getting merged with some other user's session. Which i don't understand. Is it possible in Jboss clustering that 2 user's session can get merged ?

      Is there any way to guarantee that each time a new session should get created?

      For your information I am using struts 1.1, jboss-4.2.0.GA and mysql as DB.

      jboss-4.2.0.GA is running in clustered mode, there 2 nodes in cluster env.

      Any help would greatly appreciated.

        • 1. Re: Session is getting merge with other session
          brian.stansberry

          I've found that different people mean different things when they say "clustered". Just to be certain, please confirm that the application's web.xml includes the

          <distributable/>


          tag.

          If yes, please post the content of your jboss-web.xml file, if you have one.

          Also, you use the word "merged". When I hear that I think, for example, the 2nd page shows one user's name and another user's address, or something like that. A combination of data. I can't imagine how that would happen. I can imagine 2 users ending up with the same session id, and thus one user seeing the others data (but none of their own.) However, I've never heard of that happening with clustered webapps.

          • 2. Re: Session is getting merge with other session
            igain

            Yes, I am using

            <distributable/>
            in my web.xml though I am not using any jboss-web.xml.

            I think i have used the wrong term "merged" . I should have been specific which is your 2nd statement "I can imagine 2 users ending up with the same session id, and thus one user seeing the others data (but none of their own.)"

            This might be possiblity that user getting same session id and ending up seeing other's user data.

            Even i never heard or seen this kind of problem.

            I tried to replicate the problem at my end but I was getting all correct information on next page, I mean on 2 different mahchines i tried to submit data at the same time and i was getting 2 different session ids.

            Would it help if i put
            session.invalidate()
            at the end, where application finish processing.

            • 3. Re: Session is getting merge with other session
              brian.stansberry

              If at the end of your application workflow, there is a natural place to do session.invalidate(), then sure, I encourage you to do that. That will save you memory.

              Session ids are generated from a VM singleton, using a random generator seeded by a timestamp and the VM's free memory (which are unlikely to be duplicated across VMs in a cluster). The class follows, in case you are interested. I've never heard a case of this algorithm generating noticeable duplicate ids. I have seen reports on this forum of non-clustered webapps getting duplicate ids when more than one JBoss instance is on the same machine. But clustered session ids use a different algorithm.

              Have you heard of more than 1 case of this? If you have, that would in my mind pretty much rule out a chance session id collision.

              Anyway, invalidating the session if you know its done would reduce the already extremely low chance of a problem from session id collision.

              Here's the SessionIDGenerator class:

              /*
               * JBoss, Home of Professional Open Source.
               * Copyright 2006, Red Hat Middleware LLC, and individual contributors
               * as indicated by the @author tags. See the copyright.txt file in the
               * distribution for a full listing of individual contributors.
               *
               * This is free software; you can redistribute it and/or modify it
               * under the terms of the GNU Lesser General Public License as
               * published by the Free Software Foundation; either version 2.1 of
               * the License, or (at your option) any later version.
               *
               * This software is distributed in the hope that it will be useful,
               * but WITHOUT ANY WARRANTY; without even the implied warranty of
               * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
               * Lesser General Public License for more details.
               *
               * You should have received a copy of the GNU Lesser General Public
               * License along with this software; if not, write to the Free
               * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
               * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
               */
              package org.jboss.web.tomcat.service.session;
              
              import java.util.Collection;
              import java.util.HashSet;
              import java.util.Iterator;
              import java.util.Random;
              import java.security.MessageDigest;
              import java.security.NoSuchAlgorithmException;
              import java.security.SecureRandom;
              
              import org.jboss.logging.Logger;
              
              /**
               * Unique session id generator
               *
               * @author Ben Wang
               */
              public class SessionIDGenerator
              {
               protected final static int SESSION_ID_BYTES = 16; // We want 16 Bytes for the session-id
               protected final static String SESSION_ID_HASH_ALGORITHM = "MD5";
               protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
               protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
               protected Logger log = Logger.getLogger(SessionIDGenerator.class);
              
               protected MessageDigest digest = null;
               protected Random random = null;
               protected static final SessionIDGenerator s_ = new SessionIDGenerator();
              
               protected String sessionIdAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*";
              
               public static SessionIDGenerator getInstance()
               {
               return s_;
               }
              
               /**
               * The SessionIdAlphabet is the set of characters used to create a session Id
               */
               public void setSessionIdAlphabet(String sessionIdAlphabet)
               {
               if (sessionIdAlphabet.length() != 65) {
               throw new IllegalArgumentException("SessionIdAlphabet must be exactly 65 characters long");
               }
              
               checkDuplicateChars(sessionIdAlphabet);
              
               this.sessionIdAlphabet = sessionIdAlphabet;
               }
              
               protected void checkDuplicateChars(String sessionIdAlphabet) {
               char[] alphabet = sessionIdAlphabet.toCharArray();
               for (int i=0; i < alphabet.length; i++) {
               if (!uniqueChar(alphabet, sessionIdAlphabet)) {
               throw new IllegalArgumentException("All chars in SessionIdAlphabet must be unique");
               }
               }
               }
              
               // does a character appear in the String once and only once?
               protected boolean uniqueChar(char c, String s) {
               int firstIndex = s.indexOf(c);
               if (firstIndex == -1) return false;
               return s.indexOf(c, firstIndex + 1) == -1;
               }
              
               /**
               * The SessionIdAlphabet is the set of characters used to create a session Id
               */
               public String getSessionIdAlphabet() {
               return this.sessionIdAlphabet;
               }
              
               public synchronized String getSessionId()
               {
               String id = generateSessionId();
               if (log.isDebugEnabled())
               log.debug("getSessionId called: " + id);
               return id;
               }
              
              
               /**
               * Generate a session-id that is not guessable
               *
               * @return generated session-id
               */
               protected synchronized String generateSessionId()
               {
               if (this.digest == null)
               {
               this.digest = getDigest();
               }
              
               if (this.random == null)
               {
               this.random = getRandom();
               }
              
               byte[] bytes = new byte[SESSION_ID_BYTES];
              
               // get random bytes
               this.random.nextBytes(bytes);
              
               // Hash the random bytes
               bytes = this.digest.digest(bytes);
              
               // Render the result as a String of hexadecimal digits
               return encode(bytes);
               }
              
               /**
               * Encode the bytes into a String with a slightly modified Base64-algorithm
               * This code was written by Kevin Kelley <kelley@ruralnet.net>
               * and adapted by Thomas Peuss <jboss@peuss.de>
               *
               * @param data The bytes you want to encode
               * @return the encoded String
               */
               protected String encode(byte[] data)
               {
               char[] out = new char[((data.length + 2) / 3) * 4];
               char[] alphabet = this.sessionIdAlphabet.toCharArray();
              
               //
               // 3 bytes encode to 4 chars. Output is always an even
               // multiple of 4 characters.
               //
               for (int i = 0, index = 0; i < data.length; i += 3, index += 4)
               {
               boolean quad = false;
               boolean trip = false;
              
               int val = (0xFF & (int) data);
               val <<= 8;
               if ((i + 1) < data.length)
               {
               val |= (0xFF & (int) data[i + 1]);
               trip = true;
               }
               val <<= 8;
               if ((i + 2) < data.length)
               {
               val |= (0xFF & (int) data[i + 2]);
               quad = true;
               }
               out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
               val >>= 6;
               out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
               val >>= 6;
               out[index + 1] = alphabet[val & 0x3F];
               val >>= 6;
               out[index + 0] = alphabet[val & 0x3F];
               }
               return new String(out);
               }
              
               /**
               * get a random-number generator
               *
               * @return a random-number generator
               */
               protected synchronized Random getRandom()
               {
               long seed;
               Random random = null;
              
               // Mix up the seed a bit
               seed = System.currentTimeMillis();
               seed ^= Runtime.getRuntime().freeMemory();
              
               try
               {
               random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM);
               }
               catch (NoSuchAlgorithmException e)
               {
               try
               {
               random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
               }
               catch (NoSuchAlgorithmException e_alt)
               {
               log.error("Could not generate SecureRandom for session-id randomness", e);
               log.error("Could not generate SecureRandom for session-id randomness", e_alt);
               return null;
               }
               }
              
               // set the generated seed for this PRNG
               random.setSeed(seed);
              
               return random;
               }
              
               /**
               * get a MessageDigest hash-generator
               *
               * @return a hash generator
               */
               protected synchronized MessageDigest getDigest()
               {
               MessageDigest digest = null;
              
               try
               {
               digest = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM);
               }
               catch (NoSuchAlgorithmException e)
               {
               log.error("Could not generate MessageDigest for session-id hashing", e);
               return null;
               }
              
               return digest;
               }
              
               public static void main(String[] args)
               {
               SessionIDGenerator gen = SessionIDGenerator.getInstance();
              
               HashSet set = new HashSet();
               String id = null;
               for (int i = 0; i > -1; i++)
               {
               id = gen.getSessionId();
              
               if (set.add(id) == false)
               {
               System.out.println(i + " FAILED -- duplicate id " + id);
               break;
               }
              
               if (i % 1000 == 0 && i > 0)
               {
               System.out.println("Tested " + i + " session ids");
               }
               if (i % 50000 == 0 && set.size() > 450000)
               {
               System.out.println("Discarding...");
               int k = 0;
               int discarded = 0;
               for (Iterator it = set.iterator(); it.hasNext() && discarded < 50000; k++)
               {
               it.next();
               if (k % 10 == 0)
               {
               it.remove();
               discarded++;
               }
               }
               System.out.println("Discarding completed");
               }
               }
               }
              }
              


              • 4. Re: Session is getting merge with other session
                igain

                2 end user reporting that they are seeing some other user's data and they also gave us the name and other info of that user which they were seeing on screen and i did check back in our db and those user are valid user who submit their information via our application.

                So i can't rule out, that session is not getting duplicated. However I never heard or seen session is getting duplicated in person. I have been testing so many times and never got other user's information

                Okay I have put the

                session.invalidate()
                at the end of application workflow process.

                Hoping it would reduce the chance of session collision. I am also logging the session id if it's get duplicated.

                Thanks for your support

                I would monitor

                • 5. Re: Session is getting merge with other session
                  brian.stansberry

                   

                  2 end user reporting that they are seeing some other user's data and they also gave us the name and other info of that user which they were seeing on screen and i did check back in our db and those user are valid user who submit their information via our application.


                  I take it these 2 users didn't see each others' information, but rather 2 other peoples' information? That is there were 4 users involved; just that only 2 made a report.

                  Thanks for the report. Yes, please report back if you find any more information. I'll think about any other way this kind of problem could happen.

                  • 6. Re: Session is getting merge with other session
                    igain

                    Yes you are correct these 2 users doesn't see each other's information but they see rather 2 other user's information.

                    Yeah definaitly I will report it back whatever observations i find.

                    Thanks once again.

                    • 7. Re: Session is getting merge with other session
                      igain

                      So far I haven't received any session collision issue after putting

                      session.invalidate()
                      at the end of application workflow process.



                      • 8. Re: Session is getting merge with other session
                        davewebb

                        I am seeing this problem as well. I am using JBoss 4.2.3 behind mod_jk for load balancing. I have 4 nodes in the cluster. I use REPL_ASYNC for session duplication.

                        I do have

                        <distributable/>
                        in my web.xml

                        Here is my jboss-web.xml

                        <jboss-web>
                         <replication-config>
                         <replication-trigger>SET_AND_NON_PRIMITIVE_GET</replication-trigger>
                         <replication-granularity>attribute</replication-granularity>
                         </replication-config>
                        </jboss-web>


                        I probably have about 5000 sessions generated per day and my session timeout is 60 minutes.

                        I dont really have a predefined workflow where I can invalidate the session, and although I have a logout use case, I cant make the users click it to invalidate the session. Any suggestions for me?

                        Thanks!

                        • 9. Re: Session is getting merge with other session
                          brian.stansberry

                          Dave,

                          I missed your post in October. Yours and igain's are the only reports I've had of this occuring. It's obviously a significant concern.

                          How frequently are you seeing this?

                          Only suggestions I can make involve code changes:

                          1) To tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java add

                           @Override
                           protected String getNextId()
                           {
                           while (true)
                           {
                           String id = super.getNextId();
                           if (sessions_.containsKey(id) || unloadedSessions_.containsKey(id))
                           {
                           continue;
                           }
                           else
                           {
                           return id;
                           }
                           }
                           }


                          That's in later version of the class.

                          2) The SessionIDGenerator class itself was recently changed, primarily to support use of /dev/urandom as a source of random bytes. You could look at porting some of that back to the 4.2.3 version. Current version of the class is at https://svn.jboss.org/repos/jbossas/trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/SessionIDGenerator.java

                          I've tested the SessionIDGenerator and created millions of IDs without duplicates. So any info on when/how this happens would be most appreciated.

                          • 10. Re: Session is getting merge with other session
                            davewebb

                            Brian,

                            It was reported to me in October, then again today. I log the sessionId when a user logs into my app, and today I could see that the sessionId

                            hGbGpyqSV2CPfJKGZi0KGg**.node1

                            was given to one user at 1:49PM and then to another user at 4:43PM. The first user complained that at 4:45PM she was seeing "Someone else's data". It is disturbing that the duplicate Id came from the same cluster node.

                            I could probably run a query against the access table to see how often it is happening if that would help. However, it appears that the fix you are recommending be made in 4.2.3 already exists in another branch. After which version of JBoss AS is that fix applied?

                            I also read that this can happen when sessionIds are recycled, and when the session cookie is being used in the URL (such as a bookmarked page with jsessionid) that JBoss will use the sessionId passed in without creating a new one.

                            http://kbase.redhat.com/faq/docs/DOC-17273

                            Is that true and will setting this value in the Connector help?

                            emptySessionPath=false


                            Thank you for your help. Upgrading to a newer version of JBoss is acceptable if needed, but a short term fix could help buy me a little more time to manage the upgrade.

                            • 11. Re: Session is getting merge with other session
                              jfclere

                              http://kbase.redhat.com/faq/docs/DOC-17273 is right but you must be aware that it changes the cookie session path to /your_app which may have side effect if you have more that one context deployed.

                              "when the session cookie is being used in the URL" I guess you mean when the session cookie is urlencoded (no cookies)
                              those sessionid WON'T be reused.

                              • 12. Re: Session is getting merge with other session
                                davewebb

                                So what I understand is that if I have only 1 app deployed in the cluster, or if I have multiple apps that dont rely on sharing sessionIds, then turning off the recycling will guarantee a new sessionId is generated for each new session. Is that accurate?

                                Thanks.

                                • 13. Re: Session is getting merge with other session
                                  jfclere

                                  Normally yes. If not there is a bug somewhere.

                                  • 14. Re: Session is getting merge with other session
                                    davewebb

                                    Brian,

                                     

                                    I am am idiot, and I probably shouldn't admit to this, but I found my problem.  We were storing the user's session as a instance varaible in our base servlet that all servlets inherit from.  Need I say more.   Its one of those classes you never look at, you just extend it and it works like a champ for 4 years.

                                     

                                    I have refactored everything to be thread safe in the servlet container and I dont expect any of these session mix ups again.

                                     

                                    Thanks for all the help.

                                    Dave

                                    1 2 Previous Next