management example dofilter tomcat login session-cookies jsessionid

tomcat - example - java session management



cómo actualizar la cookie JSESSIONID después de iniciar sesión (10)

Un producto en el que trabajo recibió una dura auditoría de seguridad por parte de un cliente potencial y les molesta que Tomcat establezca una cookie JSESSIONID antes de que la autenticación haya ocurrido. Es decir, Tomcat establece esta cookie cuando se carga nuestra página de inicio de sesión sin estado, pero antes de iniciar sesión.

Sugieren cualquiera de los siguientes:

  1. emite una nueva cookie JSESSIONID después de iniciar sesión
  2. evitar que una cookie JSESSIONID se establezca en primer lugar en la página de inicio de sesión (es decir, antes de que se haya realizado la autenticación)

He estado analizando todo lo relacionado con JSESSIONID en este sitio y no puedo encontrar una respuesta fácil. Solo espero algunas ideas. Mis mejores soluciones para cada uno son:

  1. justo después de iniciar sesión, clone la sesión (menos la identificación) copiando todos los atributos, invalidando la sesión anterior, creando una nueva, copiando los valores, asociándola con la solicitud y esperando que funcione.
  2. cree un filtro de servlet al final de la cadena que elimine la cookie JSESSIONID antes de que la página de inicio de sesión se cargue inicialmente. Y luego, espero que la solicitud de inicio de sesión funcione sin un conjunto de JSESSIONID.

Tengo que dormir un poco, pero los intentaré por la mañana. Sería increíble recibir comentarios o mejores sugerencias de personas mucho más inteligentes que yo, como tú.

De todos modos, publicaré mis resultados aquí porque parece que muchas otras personas han querido hacer algo similar.


¿El problema es que JSESSIONID está visible en el navegador o que se establece en una cookie? Supongo que es lo último en tu caso.

1. publicar una nueva cookie JSESSIONID después de iniciar sesión

Este es el comportamiento predeterminado de Tomcat si cambia de http a https en el momento del inicio de sesión. El anterior se descarta y se genera uno nuevo.

Si su inicio de sesión está por encima de http, supongo que es otro problema de seguridad para los auditores;)

¿O todas sus páginas están sobre https?


Al usar la primavera, debe usar SessionFixationProtectionStrategy .

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

Al inspeccionar el código fuente , verá que esto es similar al enfoque de harsha89: lo hará

  1. crea una nueva sesión
  2. atributos de transferencia de la sesión anterior.

Dos cosas que he encontrado que podrían ser útiles para otros.

  1. Si está utilizando Apache Wicket, hay una solución para esto después de la versión 1.4. Mi aplicación todavía está en 1.3, así que no me di cuenta, pero pude realizar una copia de seguridad del puerto muy fácilmente en mi propia clase de WebSession. Wicket 1.4 agrega un método replaceSession () a WebSession, que funciona muy bien. Puede llamarlo justo después de la autenticación y obtendrá un nuevo JSESSIONID. Básicamente resolvió este problema para mí. Más información aquí: issues.apache.org/jira/browse/WICKET-1767 .

  2. Hay una válvula Apache Tomcat disponible después de la versión 5.5.29 que puede agregar a context.xml. Se encargará de emitir un nuevo JSESSIONID después de la autenticación. Más información está disponible aquí: https://issues.apache.org/bugzilla/show_bug.cgi?id=45255 . La entrada de la válvula se vería así: <Valve className="org.apache.catalina.authenticator.FormAuthenticator" changeSessionIdOnAuthentication="true"/>


He seguido la siguiente manera para regenerar la nueva sesión de la sesión anterior. Espero que se beneficie de ello.

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


No actualizarás después, sino justo antes. Cuando ejecute la acción de inicio de sesión, haga primero:

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

Entonces hazlo:

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

Para tu información, lo que estás resolviendo con este truco es http://www.owasp.org/index.php/Session_Fixation

Por último, puede desactivar la creación automática de sesiones y solo crear la sesión cuando realmente lo necesite. Si usa JSP lo hace de la siguiente manera:

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


No puedo comentar la respuesta de @ cherouvim anteriormente porque no tengo suficientes puntos. La nueva ID de sesión se debe establecer "después" de que el usuario inicie sesión con éxito, para evitar la fijación de la sesión. Trataré de explicar mi razonamiento.

La fijación de sesión significa efectivamente que un atacante de alguna manera engañó a un usuario para que use un valor conocido para el atacante. En aras de la simplicidad, supongamos que el atacante se acercó al escritorio del usuario, usó Firebug y editó las cookies del usuario. Ahora cuando el usuario inicia sesión, se iniciará sesión con la cookie controlada por el atacante. Como el atacante también conoce este valor, actualizará su navegador y se les proporcionarán los recursos asignados a esa ID de sesión (los recursos de la víctima). Esa es la fijación de la sesión. ¿Correcto?

Ahora digamos que ejecutamos una session.invalidate antes de que el usuario de la víctima iniciara sesión. Digamos que la cookie inicialmente tenía un valor abc. Al ejecutar la sesión, invalide el valor que se borra abc de la sesión del servidor.

Ahora viene la parte en la que no estoy de acuerdo. Lo que sugiere es generar una nueva sesión antes de que el usuario realmente inicie sesión (ingrese nombre de usuario y contraseña, y haga clic en enviar). Esto sin duda causará que se genere una nueva cookie, pero estará en el navegador del usuario antes de iniciar sesión. Entonces, si un atacante puede editar nuevamente la cookie "prelogin", el ataque aún persiste, ya que la misma cookie se usará incluso después de que el usuario inicie sesión.

Creo que este es el flujo correcto.

  • El usuario hace un GET /login.html
  • Volver a la página de inicio de sesión con la cookie que está actualmente allí en el navegador
  • El usuario ingresa las credenciales y hace clic en enviar
  • La aplicación verifica las credenciales
  • Al encontrar que las credenciales eran correctas. session.invalidate () se ejecuta ... destruyendo la cookie anterior.
  • AHORA genere la nueva cookie usando request.getSession (true)

Lo que esto significa es que, incluso si un atacante logra engañarlo para que use un valor controlado antes de iniciar sesión, usted todavía está protegido ... a medida que la aplicación cambia forzosamente el valor después de iniciar sesión.

Aquí hay un buen blog sobre este tema: https://blog.whitehatsec.com/tag/session-fixation/


Si está utilizando Tomcat y desea aplicarlo globalmente a todos sus servlets que usan el mecanismo de autenticación de Tomcat, puede escribir una válvula para forzar este comportamiento, como se muestra en este código de ejemplo.


Si está utilizando la versión anterior de jboss como jboss 4, simplemente llamando a request.getSession (true) después de la llamada session.invalidate () no cambiará la identificación de la sesión.

Si no desea utilizar la válvula y desea cambiar la identificación de la sesión en la clase de acción, puede archivarse utilizando la reflexión porque CatalinaRequest no estará disponible directamente en su clase de acción.

Código de muestra

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; }


HttpServletRequest.changeSessionId() se puede usar para cambiar la ID de la sesión en cualquier momento.


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