Подтвердить что ты не робот

Как отключить разрешение параметров входа, переданных в качестве параметров URL/из URL-адреса

Приложение регистрирует все запрошенные url s. Это означает, что критически важно не проверять подлинность с использованием параметров url, потому что это приведет к ситуации, когда журналы заполнены парами t21. По этой причине я настроил spring-security для чтения параметров из request-body. Это делается путем добавления следующей строки в request-header:

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

Тело будет:

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

Это нормально, но QA заставляет меня отключить возможность аутентификации через URL-параметры. В настоящий момент POST на следующий URL-адрес также будет аутентифицироваться:

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

Кто-нибудь знает трюк, чтобы отключить этот параметр? Предпочтительно аннотация.

В связи с комментарием я решил добавить несколько подробностей к моей проблеме. Мой spring-security настроен с помощью WebSecurityConfigurerAdapter. У меня

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

Это делает Spring поиск данных для входа в обоих параметрах и в теле. Я хочу отключить поиск этих параметров в URL-адресе.

4b9b3361

Ответ 1

Это делает Spring поиск данных для входа в обоих параметрах и в теле. Я хочу отключить поиск этих параметров в URL-адресе.

Я считаю, что это невозможно, так как это поведение не реализовано Spring, а не сам JavaEE.

HttpServletRequest.getParameter doc:

Возвращает значение параметра запроса как String или null, если параметр не существует. Параметры запроса - дополнительная информация, отправленная с запросом. Для HTTP-сервлетов параметры содержатся в строке запроса или размещены данные формы.

Но вы можете попробовать изменить это с помощью фильтра, который должен выглядеть примерно так:

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 Хаим Раман предложил другое решение, которое использует существующий фильтр вместо представляя новую. Только я предлагаю переопределить obtainUsername() и obtainPassword() вместо attemptAuthentication().

Ответ 2

Насколько я знаю и интуитивно понятен, как сказал jhan, подходящим решением было бы использовать аннотацию @RequestMapping(value="/login", method="RequestMethod.POST"). Затем, независимо от того, какие параметры пользователь может передать с URL-адресом, оба URL и URI всегда будут по умолчанию /login. И это тот документ, который будет документировать. Не пары имени пользователя и пароля, но "http://localhost:8080/login" или независимо от вашего порта.

Ответ 3

Я хотел бы предложить альтернативу, основанную на spring -security rater, а затем обходной путь, предложенный chimmi.

Этот ответ дает решение проблемы, предложенной xenteros на bres26, как а

Отменить отмену реализации UserPasswordAuthenticationFilter

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!");

        }
    }

 }

Вам нужно заменить свою собственную реализацию на существующую (см. doc здесь)

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

Преимущества: на основе spring безопасности и гибкости изменений.
Недостаток. К сожалению, я нашел spring конфигурацию Java очень сложно установить и прочитать

EDIT: Я принял chimmi комментарий и переопределил getUsername и getPassword
Исходный код можно найти в github.

Ответ 4

Вы можете добиться этого, изменив UsernamePasswordAuthenticationFilter RequestMatcher. Например:

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()
                ...
        }
}

ПРИМЕЧАНИЕ: нижеприведенное требование не предотвращает выдачу запроса GET (и, следовательно, утечки учетных данных). Это действительно зависит от пользовательского интерфейса, чтобы этого не произошло.

Это хорошо, но QA заставляет меня отключить возможность аутентификация через URL-параметры.