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




domain from (5)

Приложение регистрирует все запрошенные url . Это означает, что критически важно не проверять подлинность с использованием параметров url, потому что это приведет к ситуации, когда журналы заполнены парами (login=abc&password=123) . По этой причине я настроил 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-адресе.


Answers

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


Я хотел бы предложить альтернативу, основанную на весенней безопасности, тогда обходной путь, предложенный .

Этот ответ дает решение проблемы, предложенной 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!");

        }
    }

 }

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

@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 Java Config очень сложно установить и прочитать

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


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


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

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-параметры.


Вы можете вызвать другой конструктор с помощью this(...) ключевого слова (когда вам нужно вызвать конструктор из того же класса) или ключевое слово super(...) (когда вам нужно вызвать конструктор из суперкласса).

Однако такой вызов должен быть первым утверждением вашего конструктора. Чтобы преодолеть это ограничение, используйте этот ответ .





java spring spring-security spring-boot httprequest