Preventing spring-security to redirect invalid url

2019-03-05 13:33发布

问题:

I've setup a spring-boot + spring-mvc + spring-security project.

Everything work as expected right now except for the invalid urls.

If I issue:

http://siteaddr.com/invalid/url

I expect to see my 404 not found page, but spring-security redirects to login page first and after authentication shows 404 not found!

I don't think this is how it should work!

Here is my Websecurity config:

package com.webitalkie.webapp.config;

import java.util.EnumSet;

import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

import com.webitalkie.webapp.security.DatabaseUserDetailsServic;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DatabaseUserDetailsServic userDetailsService;
    @Autowired
    private ServletContext servletContext;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        servletContext.getFilterRegistration(AbstractSecurityWebApplicationInitializer
                .DEFAULT_FILTER_NAME).addMappingForUrlPatterns(EnumSet
                        .allOf(DispatcherType.class), false, "/*");

        http.csrf().disable();
        http.authorizeRequests()
        .antMatchers("/home/", "/home", "/home/index", "/", "/favicon.ico").permitAll()
        .antMatchers("/contents/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/home/loginsec").failureUrl("/loginsecerror").permitAll()
        .and()
        .logout()
        .logoutUrl("/home/logout")
        .logoutSuccessUrl("/home/index")
        .invalidateHttpSession(true);

    }

    @Override
    @org.springframework.beans.factory.annotation.Autowired
    protected void configure(
            org.springframework.security.config.annotation
            .authentication.builders.AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
    }

    public PasswordEncoder getPasswordEncoder() {

        return new BcryptPasswordEncoder(11);
    }
}

Do you guys have any idea?

回答1:

To customize your particular use case apply the inverted logic as suggested. You could do like this:

1) Replace

.anyRequest().authenticated()

by

.anyRequest().anonymous()

2) Add

.antMatchers("/protected-urls/**").authenticated()

The rule in 2) must come before that in 1) as the first match applies. Unless you have a common url prefix for protected resources you'll have to declare all the authenticated urls one by one.

You can also apply additional configuration overriding the

public void configure(WebSecurity web)...

for example to ignore static resources:

web.ignoring().antMatchers("/favicon.ico", "*.css")

Hope that helps.



回答2:

This is a security feature, not a problem.

Your security model is "deny all unless explicitly allowed". If a request path is protected (i.e. doesn't match an explicitly permitAll path), then you would not want to reveal that it does not exist until the user was authenticated. In certain situations the 404 could leak private information

.../user/jones is 404? Hmm... something happened to Jones

This is the reason well designed login forms don't tell you "user not found" or "invalid password", and instead just say "invalid credentials" in all failure cases to avoid giving away too much.

The only way to get invalid URLs to bypass security would be to invert your security model, making everything public unless explicitly protected ("allow unless explicitly prohibited"). Which has its own set of issues, such as having to remember to update the definition every time a new root path is created.