如何禁用parsing作为URL参数/从URL传递的login参数
应用程序logging所有请求的url
。 这意味着,不使用url参数进行身份validation是非常重要的,因为这会导致日志满满的情况(login=abc&password=123)
。 因为这个原因,我configuration了spring-security
从request-body
读取参数。 这是通过将以下行添加到request-header
:
'Content-Type': 'application/x-www-form-urlencoded'
身体将是:
{'login':'admin', 'password':'password'}
这很好,但QA迫使我禁用通过URL参数进行身份validation的可能性。 目前,对以下URL的POST也将进行身份validation:
https://example.com/foo?login=admin&password=password
有谁知道一个技巧来禁用此选项? 最好用注释。
由于评论我决定添加一些更多的细节,我的问题。 我的spring-security使用WebSecurityConfigurerAdapter
configuration。 我有
http.usernameParameter("login") .passwordParameter("password") (...)
这使得Spring
在参数和正文中searchlogin数据。 我希望禁用searchURL中的这些参数。
这使得Spring在参数和正文中searchlogin数据。 我希望禁用searchURL中的这些参数。
我相信这是不可能的,因为这个行为不是由Spring而是由JavaEE本身实现的。
HttpServletRequest.getParameter doc指出:
以Stringforms返回请求参数的值;如果参数不存在,则返回null。 请求参数是与请求一起发送的额外信息。 对于HTTP Servlet, 参数包含在查询string或发布的表单数据中 。
但你可以尝试改变这个filter应该看起来像这样:
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拉曼提出了另一种解决scheme ,使用现有的filter,而不是引入一个新的。 只有我会build议覆盖obtainUsername()
和obtainPassword()
而不是attemptAuthentication()
。
据我所知,直觉就像jhan所说的,适当的解决scheme是使用注解@RequestMapping(value="/login", method="RequestMethod.POST")
。 然后,无论用户使用哪个parameter passingURL,URL和URI都将默认为/ login。 这就是logging器将logging的内容。 不是用户名和密码对,而是"http://localhost:8080/login"
,或者你的端口号。
我想build议一个基于spring-security rater的替代scheme,然后是chimmi提出的解决方法。
这个答案提供了一个解决scheme,由xenterosbuild议在bres26答案以及
覆盖现有的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!"); } } }
您需要用现有的实现来replace自己的实现(请参阅文档)
@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中find源代码。
你可以通过修改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参数进行身份validation的可能性。