web-dev-qa-db-fra.com

comment actualiser le cookie JSESSIONID après la connexion

Un produit sur lequel je travaille a été soumis à un audit de sécurité difficile par un client potentiel et ceux-ci sont mécontents que Tomcat définisse un cookie JSESSIONID avant l'authentification. C'est-à-dire que Tomcat définit ce cookie lors du chargement de notre page de connexion sans état, mais avant la connexion.

Ils suggèrent l'une des suivantes:

  1. émettre un nouveau cookie JSESSIONID après la connexion
  2. empêcher qu'un cookie JSESSIONID soit défini en premier lieu sur la page de connexion (c'est-à-dire avant l'authentification)

J'ai parcouru tout ce qui a trait à JSESSIONID sur ce site et je ne trouve pas de réponse facile. J'espère juste quelques idées. Mes meilleures solutions pour chacune sont:

  1. juste après la connexion, clonez la session (sans l'identifiant) en copiant tous les attributs, en invalidant l'ancienne session, en créant une nouvelle, en copiant les valeurs, en l'associant à la demande et en espérant que cela fonctionne.
  2. créez un filtre de servlet à la toute fin de la chaîne qui supprime le cookie JSESSIONID avant le chargement initial de la page de connexion. Et espérons ensuite que la demande de connexion fonctionnera sans un ensemble JSESSIONID.

Je dois dormir un peu, mais j'essaierai de les faire demain matin. Ce serait génial de recevoir des commentaires ou de meilleures suggestions de la part de personnes plus intelligentes que moi - comme vous!

Quoi qu'il en soit, je posterai mes résultats ici car il semble que beaucoup d'autres personnes aient voulu faire quelque chose de similaire.

25
Nathan Beach

Vous n'actualiserez pas après mais juste avant. Lors de l'exécution de l'action de connexion, faites d'abord:

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

Alors fais:

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

FYI ce que vous résolvez avec cette astuce est http://www.owasp.org/index.php/Session_Fixation

Enfin, vous pouvez désactiver la création automatique de session et ne créer la session que lorsque vous en avez vraiment besoin. Si vous utilisez JSP, vous le faites en:

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

Je ne peux pas commenter la réponse de @ cherouvim ci-dessus car je n'ai pas assez de points. Le nouvel identifiant de session doit être défini "après" la connexion de l'utilisateur, afin d'éviter une fixation de session. Je vais essayer d'expliquer mon raisonnement.

La fixation de session signifie en réalité qu'un attaquant a dupé un utilisateur en lui demandant d'utiliser une valeur connue de celui-ci. Pour simplifier, supposons que l'attaquant se soit rendu au bureau de l'utilisateur, ait utilisé Firebug et modifié le cookie de l'utilisateur. Désormais, lorsque l'utilisateur se connectera, il sera connecté avec le cookie contrôlé par l'attaquant. Comme l'attaquant connaît également cette valeur, il actualisera son navigateur et les ressources associées à cet ID de session (les ressources de la victime) leur seront servies. C'est fixation de session. Correct?

Maintenant, supposons que nous ayons exécuté session.invalidate avant que l'utilisateur victime se connecte. Supposons que le cookie ait initialement une valeur abc. Lors de l'exécution de session.invalidate, la valeur abc est purgée de la session du serveur.

Vient maintenant la partie où je ne suis pas d'accord. Ce que vous suggérez, c'est de générer une nouvelle session avant que l'utilisateur ne se connecte (entre le nom d'utilisateur et le mot de passe, puis cliquez sur soumettre). Cela générera sans aucun doute la création d'un nouveau cookie, mais il sera affiché dans le navigateur de l'utilisateur avant sa connexion. Donc, si un attaquant peut éditer à nouveau le cookie "prelogin", l'attaque persiste, car le même cookie sera utilisé même après la connexion de l'utilisateur.

Je pense que c'est le bon flux.

  • L'utilisateur fait un GET /login.html
  • Retournez la page de connexion avec le cookie présent dans le navigateur
  • L'utilisateur entre les informations d'identification et clique sur soumettre
  • L'application vérifie les informations d'identification
  • En constatant que les informations d'identification étaient correctes. la session.invalidate () est exécutée .. détruisant l'ancien cookie.
  • MAINTENANT générer le nouveau cookie en utilisant request.getSession (true)

Cela signifie que même si un attaquant parvient à vous persuader d'utiliser une valeur contrôlée avant de vous connecter, vous êtes toujours protégé ... car l'application modifie de force la valeur après votre connexion.

Voici un bon blog sur ce problème - https://blog.whitehatsec.com/tag/session-fixation/

4
LDE

J'ai suivi la manière suivante pour régénérer la nouvelle session de l'ancienne session. J'espère que vous en bénéficierez. 

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));
        }
    }
3
harsha89

Le problème est-il que le JSESSIONID est visible dans le navigateur ou qu'il est défini dans un cookie? Je suppose que c'est le dernier cas dans votre cas.

1. publier un nouveau cookie JSESSIONID après la connexion

Ceci est le comportement par défaut de Tomcat si vous passez de http à https / au moment de la connexion. L'ancien est jeté et un nouveau est généré.

Si votre login est lui-même sur http, je suppose que c'est un autre problème de sécurité pour les auditeurs;)

Ou est-ce que toutes vos pages sont sur https?

1
JoseK

J'ai trouvé deux choses qui pourraient aider les autres. 

  1. Si vous utilisez Apache Wicket, il existe une solution pour cela après la version 1.4. Mon application est toujours sur la version 1.3, donc je ne m'en suis pas rendu compte, mais j'ai pu la transférer très facilement dans ma propre classe WebSession. Wicket 1.4 ajoute une méthode replaceSession () à WebSession, qui fonctionne très bien. Vous pouvez l'appeler juste après l'authentification et vous obtiendrez un nouveau JSESSIONID. Cela a fondamentalement résolu ce problème pour moi. Plus d'infos ici: https://issues.Apache.org/jira/browse/WICKET-1767

  2. Une version Apache Tomcat Valve disponible après la version 5.5.29 peut être ajoutée au fichier context.xml. Il gérera l’émission d’un nouveau JSESSIONID après l’authentification. Plus d'informations sont disponibles ici: https://issues.Apache.org/bugzilla/show_bug.cgi?id=45255 . L'entrée pour la vanne ressemblerait à ceci: <Valve className="org.Apache.catalina.authenticator.FormAuthenticator" changeSessionIdOnAuthentication="true"/>

1
Nathan Beach

HttpServletRequest.changeSessionId() peut être utilisé pour changer l'ID de session à tout moment.

1
bhawnesh dipu

Si vous utilisez Tomcat et souhaitez l'appliquer globalement à tous vos servlets utilisant le mécanisme d'authentification de Tomcat, vous pouvez écrire une Valve pour forcer ce comportement, comme indiqué dans cet exemple de code .

0
David Leppik

Lorsque vous utilisez Spring, vous devez utiliser SessionFixationProtectionStrategy.

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

En inspectant le code source , vous verrez que cela ressemble à l’approche de harsha89:

  1. créer une nouvelle session
  2. attributs de transfert de l'ancienne session.
0
Matthias M

Si vous utilisez l'ancienne version de jboss comme jboss 4, alors simplement appeler l'appel à request.getSession (true) après l'appel de session.invalidate () ne changera pas l'identifiant de session.

Si vous ne souhaitez pas utiliser Valve et que vous souhaitez modifier l'ID de session dans la classe d'action, vous pouvez l'archiver à l'aide de la réflexion, car CatalinaRequest ne sera pas disponible directement dans votre classe d'action.

Exemple de 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;

}
0
Rahul Suman