如何从网址

时间:2016-08-02 09:30:58

标签: java spring spring-security spring-boot httprequest

应用程序记录所有请求的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参数禁用身份验证的可能性。目前,对以下URL的POST也将进行身份验证:

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

有没有人知道禁用此选项的技巧?最好带注释。

由于评论我决定在我的问题中添加更多细节。我的配置了WebSecurityConfigurerAdapter。我有

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

这使Spring在 - 参数和正文中搜索登录数据。我希望禁用在网址中搜索这些参数。

4 个答案:

答案 0 :(得分:15)

  

这使得Spring在参数和正文中搜索登录数据。我希望禁用在网址中搜索这些参数。

我认为这是不可能的,因为Spring没有实现这种行为而不是JavaEE本身。

HttpServletRequest.getParameter doc声明:

  

以String形式返回请求参数的值,如果参数不存在,则返回null。请求参数是随请求一起发送的额外信息。对于HTTP servlet,参数包含在查询字符串或发布的表单数据中

但您可以尝试使用看起来像这样的过滤器来改变它:

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

编辑 Haim Raman建议使用现有过滤器而不是引入新过滤器的另一个solution。只有我建议覆盖obtainUsername()obtainPassword()而不是attemptAuthentication()

答案 1 :(得分:7)

我想建议一个基于spring-security rater的替代方案,然后根据chimmi建议的解决方法。

此答案提供xenterosbres26答案建议的问题的解决方案

覆盖现有的UsernamePasswordAuthenticationFilter实现

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很难设置和阅读

编辑:我接受chimmi评论并覆盖了getsUsername和obtainPassword
您可以在github中找到源代码。

答案 2 :(得分:6)

就我所知和直觉而言,就像詹提到的那样,适当的解决方案是使用注释@RequestMapping(value="/login", method="RequestMethod.POST")。然后,无论用户使用URL传递什么参数,URL和URI都将始终默认为/ login。这就是记录器将记录的内容。不是用户名和密码对,而是"http://localhost:8080/login"或任何端口。

答案 3 :(得分:6)

您可以通过修改UsernamePasswordAuthenticationFilter的{​​{1}}来实现此目的。例如:

RequestMatcher

注意:以下要求不会阻止发出GET请求(从而泄露凭据)。 UI确实不会发生这种情况。

  

没关系,但QA迫使我禁用它的可能性   通过url paramters进行身份验证。