39 votes

Comment désactiver la résolution des paramètres de connexion passés en tant que paramètres d'URL / depuis l'URL

L'application enregistre toutes demandée urls. Cela signifie, qu'il est essentiel de ne pas s'authentifier à l'aide des paramètres d'url, parce qu'il serait la cause de la situation dans laquelle les journaux sont pleins de paires (login=abc&password=123). Pour cette raison, j'ai configuré spring-security lecture des paramètres à partir d' request-body. C'est fait en ajoutant la ligne suivante à l' request-header:

'Content-Type': 'application/x-www-form-urlencoded'

Le corps sera:

{'login':'admin', 'password':'password'}

C'est beau, mais l'assurance de la qualité qui m'oblige à désactiver la possibilité de l'authentification via l'url paramétrée. Au moment d'un POST à l'URL suivante permettra également d'authentifier:

https://example.com/foo?login=admin&password=password

Quelqu'un sait-il une astuce pour désactiver cette option? Avec une annotation de préférence.

En raison du commentaire que j'ai décidé d'ajouter un peu plus de détails à mon problème. Mon est configuré avec WebSecurityConfigurerAdapter. J'ai

http.usernameParameter("login")
    .passwordParameter("password")
(...)

Cela rend Spring recherche connexion de données dans les deux paramètres et le corps. Je souhaite désactiver la recherche de ces paramètres dans l'url.

15voto

chimmi Points 1379

Ce fait Ressort de la recherche les données de connexion dans les deux paramètres et le corps. Je souhaite désactiver la recherche de ces paramètres dans l'url.

Je crois que ce n'est pas possible puisque ce comportement n'est pas mis en œuvre d'ici le Printemps plutôt que JavaEE lui-même.

HttpServletRequest.getParameter doc états:

Retourne la valeur d'un paramètre de la requête comme une Chaîne de caractères, ou null si le paramètre n'existe pas. Les paramètres de la demande sont de renseignements supplémentaires envoyé avec la demande. Pour HTTP servlets, les paramètres sont contenus dans la chaîne de requête ou posté des données de formulaire.

Mais vous pouvez essayer de modifier ce filtre qui devrait ressembler à quelque chose comme ceci:

public class DisableGetAuthFiler extends OncePerRequestFilter {
    ...

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(
                new HttpServletRequestWrapper(request) {
                    @Override
                    public String getParameter(String name) {
                        if (("login".equals(name) && getQueryString().contains("login"))
                                || ("password".equals(name) && getQueryString().contains("password"))) {
                            return null;
                        } else {
                            return super.getParameter(name);
                        }
                    }
                },
                response
        );
    }
}

EDIT Haim Raman proposé une autre solution qui utilise le filtre existant plutôt que d'introduire un nouveau. Seulement, je voudrais suggérer primordial obtainUsername() et obtainPassword() au lieu de attemptAuthentication().

8voto

Haim Points 1483

Je voudrais proposer une alternative qui est basé sur spring-security évaluateur puis une solution de contournement, comme suggéré par chimmi.

Cette réponse d'apporter une solution à la question suggérée par xenteros sur bres26 répondre ainsi

Remplacer la sortie de UsernamePasswordAuthenticationFilter mise en œuvre

public class ImprovedUsernamePasswordAuthenticationFilter 
                                    extends UsernamePasswordAuthenticationFilter {

    @Override
    protected String obtainUsername(HttpServletRequest request) {
        final String usernameParameter = getUsernameParameter();
        validateQueryParameter(request, usernameParameter);
        return super.obtainUsername(request);
    }

    @Override
    protected String obtainPassword(HttpServletRequest request) {
        final String passwordParameter = getPasswordParameter();
        validateQueryParameter(request, passwordParameter);
        return super.obtainPassword(request);
    }

    private void validateQueryParameter(HttpServletRequest request, String parameter) {
        final String queryString = request.getQueryString();
        if (!StringUtils.isEmpty(queryString)) {
            if (queryString.contains(parameter))
                throw new AuthenticationServiceException("Query parameters for login are a prohibit, use message body only!");

        }
    }

 }

Vous avez besoin de remplacer votre propre mise en œuvre avec l'existant (voir la doc ici)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home","/login").permitAll()
                .anyRequest().authenticated()
                .and()
            .logout()
                .permitAll()
                .and()
             //Replace FORM_LOGIN_FILTER with your own custom implementation
             .addFilterAt(improvedUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
               .exceptionHandling()
               .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
               .and()
            //disable csrf to allow easy testing
             .csrf().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }

    public UsernamePasswordAuthenticationFilter improvedUsernamePasswordAuthenticationFilter() throws Exception {
        UsernamePasswordAuthenticationFilter authFilter = new ImprovedUsernamePasswordAuthenticationFilter();
        authFilter.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/login", "POST")
         );
        authFilter
        .setAuthenticationManager(authenticationManager());
        authFilter
       .setAuthenticationSuccessHandler(
           new SavedRequestAwareAuthenticationSuccessHandler()
        );
       authFilter
       .setAuthenticationFailureHandler(
         new SimpleUrlAuthenticationFailureHandler("/login?error")
       );
        return authFilter;
    }
}

Avantages: il est basé sur le printemps de sécurité et flexible aux changements.
Inconvénient: Malheureusement, j'ai trouvé Printemps Java Config très difficile à définir et à lire

EDIT: j'ai accepté chimmi commentaire et remplacé obtainUsername et obtainPassword
Vous pouvez trouver le code source de github.

6voto

Bres26 Points 357

Au meilleur de ma connaissance et de mon intuition, comme l'a mentionné jhan, la solution appropriée serait d'utiliser l'annotation @RequestMapping(value="/login", method="RequestMethod.POST") . Ensuite, quels que soient les paramètres que l'utilisateur puisse transmettre avec l'URL, l'URL et l'URI utiliseront toujours / login par défaut. Et c'est ce que l'enregistreur va documenter. Pas les paires nom d'utilisateur et mot de passe, mais "http://localhost:8080/login" , ou quel que soit votre port.

6voto

Rob Winch Points 15031

Vous pouvez y parvenir en modifiant les UsernamePasswordAuthenticationFilter 's RequestMatcher . Par exemple:

 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .formLogin()
                    .withObjectPostProcessor(new ObjectPostProcessor<UsernamePasswordAuthenticationFilter>() {
                        @Override
                        public <O extends UsernamePasswordAuthenticationFilter> O postProcess(
                                O filter) {
                            AntPathRequestMatcher pathMatcher = new AntPathRequestMatcher("/login", "POST");
                            RequestMatcher noQuery = new RequestMatcher() {

                                @Override
                                public boolean matches(HttpServletRequest request) {
                                    return request.getQueryString() == null;
                                }
                            };
                            AndRequestMatcher matcher = new AndRequestMatcher(Arrays.asList(pathMatcher, noQuery));
                            filter.setRequiresAuthenticationRequestMatcher(matcher);
                            return filter;
                        }
                    })
                    .and()
                ...
        }
}
 

REMARQUE : L'exigence ci-dessous n'empêche pas l'émission d'une demande GET (et donc la fuite des informations d'identification). C’est vraiment à l’interface utilisateur de s’assurer que cela ne se produit pas.

C'est bien, mais le contrôle de la qualité m'oblige à désactiver la possibilité d'authentification via les paramètres d'URL.

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