how to refresh JSESSIONID cookie after login

不羁岁月 提交于 2019-12-02 16:17:18

You will not refresh after but just before. When executing the login action first do:

HttpSession session = request.getSession(false);
if (session!=null && !session.isNew()) {
    session.invalidate();
}

Then do:

HttpSession session = request.getSession(true); // create the session
// do the login (store the user in the session, or whatever)

FYI what you are solving with this trick is http://www.owasp.org/index.php/Session_Fixation

Lastly you can disable automatic session creation and only create the session when you really need it. If you use JSP you do that by:

<%@page contentType="text/html"
        pageEncoding="UTF-8"
        session="false"%>

I can't comment on @cherouvim's answer above as I don't have enough points. The new session ID should be set "after" the user successfully logs in, to avoid session fixation. I'll try and explain my reasoning.

Session fixation effectively means that an attacker somehow tricked a user into using a value known to the attacker. For simplicity's sake, let's assume that the attacker walked over to the user's desk, used Firebug and edited the user's cookie. Now when the user logs in, he/she will be logged in with the attacker controlled cookie. Since the attacker also knows this value he/she will refresh their browser and the resources mapped to that session ID (the victim's resources) will be served to them. That's session fixation. Correct?

Now let's say we ran a session.invalidate before the victim user logged in. Lets say the cookie initially had a value abc. On running session.invalidate the value abc is purged from the server's session.

Now comes the part where I disagree. What you suggest is to generate a new session before the user actually logs in (Enters username and password and clicks submit). This will no doubt cause a new cookie to get generated but it will be on the user's browser before they login. So if an attacker can edit the "prelogin" cookie again, the attack still persists, as the same cookie will be used even after the user logs in.

I think this is the correct flow.

  • User does a GET /login.html
  • Return Login page with whatever cookie is currently there in the browser
  • User enters credentials and clicks submit
  • Application verifies credentials
  • On finding that credentials were correct. the session.invalidate() is run ..destroying the old cookie.
  • NOW generate the new cookie using request.getSession(true)

What this means, is that even if an attacker manages to trick you into using a controlled value prior to logging in, you're still protected..as the application forcibly changes the value after you log in.

Here is a good blog about this issue - https://blog.whitehatsec.com/tag/session-fixation/

I have followed following way to regenerate the new session from old session. Hope you will be benefited from it.

private void regenerateSession(HttpServletRequest request) {

    HttpSession oldSession = request.getSession();

    Enumeration attrNames = oldSession.getAttributeNames();
    Properties props = new Properties();

    if (attrNames != null) {
        while (attrNames.hasMoreElements()) {
            String key = (String) attrNames.nextElement();
            props.put(key, oldSession.getAttribute(key));
        }

        //Invalidating previous session
        oldSession.invalidate();
        //Generate new session
        HttpSession newSession = request.getSession(true);
        attrNames = props.keys();

        while (attrNames.hasMoreElements()) {
            String key = (String) attrNames.nextElement();
            newSession.setAttribute(key, props.get(key));
        }
    }

Two things I've found that might helpful to others.

  1. If you're using Apache Wicket, there is a solution for this after version 1.4. My app is still on 1.3, so I didn't realize, but I was able to back port it very easily in my own WebSession class. Wicket 1.4 adds a replaceSession() method to WebSession, which works great. You can call it right after authentication and you'll get a new JSESSIONID. It basically solved this problem for me. More info here: https://issues.apache.org/jira/browse/WICKET-1767.

  2. There is a Apache Tomcat valve available after version 5.5.29 which you can add to context.xml. It will handle issuing a new JSESSIONID after authentication. More info is available here: https://issues.apache.org/bugzilla/show_bug.cgi?id=45255. The entry for the valve would look like this: <Valve className="org.apache.catalina.authenticator.FormAuthenticator" changeSessionIdOnAuthentication="true"/>

When using spring, you should use SessionFixationProtectionStrategy.

<property name="sessionAuthenticationStrategy" ref="sas"/>
...
<bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>

When inspecting the source code, you will see that this is similar to the approach of harsha89: It will

  1. create a new session
  2. tranfer attributes of the old session.

Is the problem that the JSESSIONID is visible in the browser or that it gets set in a cookie at all? I'm assuming it is the latter in your case.

1.issue a new JSESSIONID cookie after login

This is the default Tomcat behaviour if you switch from http to https at the time of login. The old one is discarded and a new one is generated.

If your login itself is over http, I guess that's another security issue for the auditors ;)

Or are all your pages over https?

bhawnesh dipu

HttpServletRequest.changeSessionId() can be use to change the session ID at any point of time.

If you are using Tomcat and want to apply this globally to all your servlets which use Tomcat's authentication mechanism, you can write a Valve to force this behavior, as shown in this sample code.

If you are using the older version of jboss like jboss 4 then simply calling the request.getSession(true) after session.invalidate() call will not change the session id.

If you don't want to use valve and want to change the session id in action class same can be archived using reflection because CatalinaRequest will be not available directly in your action class.

Sample code

private HttpSession changeSessionId( HttpServletRequest request )
{
    HttpSession oldSession = request.getSession( false );
    HttpSession newSession = null;

    try
    {
        //get all cookies from request
        Cookie[] cookies = request.getCookies();

        //Get all attribute from old session
        Enumeration< Object > attrNames = oldSession.getAttributeNames();

        Properties attributFromOldSession = new Properties();

        while ( attrNames.hasMoreElements() )
        {
            String key = (String)attrNames.nextElement();
            attributFromOldSession.put( key, oldSession.getAttribute( key ) );
        }

        //Actual logic to change session id

        Field catalinaRequestField;

        //Getting actual catalina request using reflection
        catalinaRequestField = request.getClass().getDeclaredField( "request" );
        catalinaRequestField.setAccessible( true ); // grant access to (protected) field
        Request realRequest = (Request)catalinaRequestField.get( request );

        //Invalidating actual request
        realRequest.getSession( true ).invalidate();
        realRequest.setRequestedSessionId( null );
        realRequest.clearCookies();

        //setting new session Id
        realRequest.setRequestedSessionId( realRequest.getSessionInternal( true ).getId() );

        //Put back the cookies
        for ( Cookie cookie : cookies )
        {

            if ( !"JSESSIONID".equals( cookie.getName() ) )
            {
                realRequest.addCookie( cookie );
            }
        }

        // put attribute from old session
        attrNames = attributFromOldSession.keys();

        while ( attrNames.hasMoreElements() )
        {
            String key = (String)attrNames.nextElement();
            newSession.setAttribute( key, attributFromOldSession.get( key ) );
        }
    }
    catch ( Exception e )
    {
        e.printStackTrace();
    }
    return newSession;

}
session=request.getSession(true);
Enumeration keys = session.getAttributeNames();     
HashMap<String,Object> hm=new HashMap<String,Object>();  
while (keys.hasMoreElements())
{
  String key = (String)keys.nextElement();
  hm.put(key,session.getValue(key));
  session.removeAttribute(key);      
}
session.invalidate();
session=request.getSession(true);
for(Map.Entry m:hm.entrySet())
{
  session.setAttribute((String)m.getKey(),m.getValue());  
  hm.remove(m);
}  
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!