J'ai une application Web qui s'exécute sur un serveur Tomcat 7. Le cookie avec l'identifiant de session a par défaut les indicateurs HttpOnly
et Secure
. Je souhaite désactiver ces indicateurs pour le cookie JSESSIONID
. Mais ça ne marchera pas. J'ai changé cela dans mon fichier web.xml
mais cela ne fonctionne pas.
<session-config>
<session-timeout>20160</session-timeout>
<cookie-config>
<http-only>false</http-only>
<secure>false</secure>
</cookie-config>
</session-config>
Je sais que c'est un risque pour la sécurité, car un attaquant est capable de voler le cookie et de pirater la session s'il a trouvé un XSS VUL.
Le cookie JSESSIONID
doit être envoyé avec HTTP et HTTPS et avec les requêtes AJAX.
Modifier:
J'ai correctement désactivé l'indicateur HttpOnly
en ajoutant l'option suivante au fichier conf/context.xml
:
<Context useHttpOnly="false">
....
</Context>
Tomcat n’a pas trouvé de solution à ce problème, mais si vous utilisez Apache comme proxy inverse, vous pouvez procéder comme suit:
Header edit* Set-Cookie "(JSESSIONID=.*)(; Secure)" "$1"
avec mod_headers
qui supprimera l’en-tête sur le chemin de retour pour supprimer le drapeau sécurisé. Pas joli mais fonctionne si c'est critique.
Si vous lisez le code de Tomcat vous trouverez:
// Always set secure if the request is secure
if (scc.isSecure() || secure) {
cookie.setSecure(true);
}
Donc, essayer de désactiver l'indicateur sécurisé sur le cookie JSESSIONID avec sessionCookieConfig.setSecure(false);
dans un écouteur ou <cookie-config><secure>false</secure></cookie-config>
dans le web.xml NE FONCTIONNE PAS car Tomcat force l'indicateur sécurisé à true si la demande est sécurisée (c'est-à-dire à partir d'une URL https ou du port SSL) .
Une solution consiste à utiliser un filtre de requête pour modifier le cookie JSESSIONID sur la réponse du serveur immédiatement après la création de la session. Voici mon implémentation (très basique):
public class DisableSecureCookieFilter implements javax.servlet.Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
request = new ForceUnsecureSessionCookieRequestWrapper((HttpServletRequest) request, (HttpServletResponse) response);
}
chain.doFilter(request, response);
}
@Override
public void destroy() { }
public static class ForceUnsecureSessionCookieRequestWrapper extends HttpServletRequestWrapper {
HttpServletResponse response;
public ForceUnsecureSessionCookieRequestWrapper(HttpServletRequest request, HttpServletResponse response) {
super(request);
this.response = response;
}
@Override
public HttpSession getSession(boolean create) {
if(create) {
HttpSession session = super.getSession(create);
updateCookie(response.getHeaders("Set-Cookie"));
return session;
}
return super.getSession(create);
}
@Override
public HttpSession getSession() {
HttpSession session = super.getSession();
if(session != null) {
updateCookie(response.getHeaders("Set-Cookie"));
}
return session;
}
protected void updateCookie(Collection<String> cookiesAfterCreateSession) {
if(cookiesAfterCreateSession != null && !response.isCommitted()) {
// search if a cookie JSESSIONID Secure exists
Optional<String> cookieJSessionId = cookiesAfterCreateSession.stream()
.filter(cookie -> cookie.startsWith("JSESSIONID") && cookie.contains("Secure"))
.findAny();
if(cookieJSessionId.isPresent()) {
// remove all Set-Cookie and add the unsecure version of the JSessionId Cookie
response.setHeader("Set-Cookie", cookieJSessionId.get().replace("Secure", ""));
// re-add all other Cookies
cookiesAfterCreateSession.stream()
.filter(cookie -> !cookie.startsWith("JSESSIONID"))
.forEach(cookie -> response.addHeader("Set-Cookie", cookie));
}
}
}
}
}
et dans le web.xml:
<filter>
<filter-name>disableSecureCookieFilter</filter-name>
<filter-class>com.xxxx.security.DisableSecureCookieFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>disableSecureCookieFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
N'oubliez pas que l'activation des cookies non sécurisés contourne une sécurité https importante! (je devais le faire pour une transition en douceur de http à https)