7 votes

Problème de sécurité de traversée de répertoire

J'ai une application web Java qui est vulnérable à une attaque de type directory transversal (aka path transversal) via l'encodage des URL. Après avoir été authentifié :

Selon les spécifications des servlets, le dossier WEB-INF n'est pas censé être accessible au public, mais cela fonctionne dans ce cas. J'utilise Websphere 5.1 avec Java 1.4, Spring Security 2.0.5 et Struts 1.3. D'après ce que j'ai lu, il semble que le problème soit lié à l'encodage, %c0%ae étant '.' (point) en UTF-8.

J'ai essayé la même chose sur une autre webapp qui fonctionne dans un environnement différent (Tomcat 6 avec Java 7, Spring Security 3 et Spring MVC) et je n'ai pas pu reproduire le problème. Cette deuxième webapp a un filtre pour forcer l'encodage des pages en UTF-8 ( org.springframework.web.filter.CharacterEncodingFilter ), j'ai donc essayé la même configuration sur la première webapp, mais cela n'a pas fonctionné. Des idées ?

Gracias.

2voto

Emmanuel Ballerini Points 288

Je vais répondre à ma propre question.
Avec les options limitées dont je disposais, j'ai fini par ajouter dans le fichier de configuration de Spring Security une règle de sécurité du type suivant

<sec:intercept-url pattern="/**/WEB-INF/**" access="no-access"/>

Il restreint l'accès à WEB-INF au rôle 'no-access' qui n'est en fait pas un rôle. Cela empêche l'accès à tous les utilisateurs. Ce n'est pas idéal mais cela fera l'affaire jusqu'à ce qu'il y ait une mise à jour.

1voto

Øyvind Skaar Points 1291

Vous pouvez corriger ou refuser ces requêtes avant qu'elles n'atteignent Websphere en les faisant passer par un autre serveur Web/applicatif ou par un autre système d'information. Pare-feu pour applications Web . Soit un autre serveur d'applications Java, soit quelque chose du genre Nginx o Vernis pourrait faire l'affaire.

Bien sûr, le real La solution consiste à effectuer une mise à niveau. Ce n'est qu'un pansement, qui pourrait être subverti. C'est vraiment la mauvaise façon de "régler" les problèmes de sécurité.

0voto

Maurice Perry Points 18154

Le filtre modifie le codage des caractères pour le corps de la requête, pas pour l'URL.

Pour définir l'encodage URL dans tomcat, vous devez ajouter un attribut dans l'élément <Connector> de server.xml :

<Connector port="8080" protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           URIEncoding="UTF-8"
           redirectPort="8443" />

0voto

Dmitri Points 4199

Si vous ne pouvez pas effectuer de mise à jour (ancien WebSphere + Java 1.4, aïe !), une solution de contournement possible (plutôt une solution de fortune, en fait) consiste à écrire un filtre simple, associé à chaque demande, qui effectue la conversion correcte du jeu de caractères et rejette les demandes non valides.

Je suis sûr qu'en creusant un peu, vous pouvez trouver une implémentation qui vérifie des choses auxquelles vous n'avez peut-être pas pensé.

Bien sûr, il reste encore 8 ans d'autres problèmes de sécurité (sans parler de la productivité).

Oups

Je n'ai pas remarqué l'ancienneté de la question.

0voto

Voici ma mise en œuvre

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author davidandrade
 */
public class RestrictURL implements Filter {

    private FilterConfig fcgConfFiltr_t;

    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(RestrictURL.class.getName());

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        fcgConfFiltr_t = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String strUrlPetici_t = req.getRequestURL().toString();
        String strUrlBase___t = strUrlPetici_t.substring(0, strUrlPetici_t.indexOf(fcgConfFiltr_t.getServletContext().getContextPath()) + fcgConfFiltr_t.getServletContext().getContextPath().length());

        try {

            res.addHeader("X-Frame-Options", "SAMEORIGIN");
            log.info("URL Req: " + strUrlPetici_t);

            if (strUrlPetici_t.toLowerCase().contains("%co") || strUrlPetici_t.toLowerCase().contains("%ae")) {
                sendErrorRedirect(req, res, "/404.jsf", new Exception("DirectoryTransversalRequired"));
            } else {
                try {
                    fcgConfFiltr_t.getServletContext().getRequestDispatcher(strUrlPetici_t).forward(request, response);
                } catch (IllegalArgumentException e) {
                    chain.doFilter(request, response);
                }
            }

        } catch (Exception e) {
            log.error("", e);
            sendErrorRedirect(req, res, "/404.jsf", e);

        }
    }

    protected void sendErrorRedirect(HttpServletRequest request, HttpServletResponse response, String errorPageURL, Throwable e) throws ServletException, IOException {
        request.setAttribute("exception", e);
        fcgConfFiltr_t.getServletContext().getRequestDispatcher(errorPageURL).forward(request, response);
    }

    @Override
    public void destroy() {
        fcgConfFiltr_t = null;
    }

}

Et ajouter un filtre à mon web.xml

<filter>
        <filter-name>DirectoryTransversalFilter</filter-name>
        <filter-class>com.sec.RestrictURL</filter-class> <!-- mandatory -->
    </filter>
    <filter-mapping>
        <filter-name>DirectoryTransversalFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X