xen*_*ros 37 java spring spring-security httprequest spring-boot
应用程序记录所有请求的urls.这意味着,使用url参数进行身份验证至关重要,因为这会导致日志中充满对的情况(login=abc&password=123).出于这个原因,我已配置spring-security为从中读取参数request-body.这是通过将以下行添加到request-header:
'Content-Type': 'application/x-www-form-urlencoded'
Run Code Online (Sandbox Code Playgroud)
身体将是:
{'login':'admin', 'password':'password'}
Run Code Online (Sandbox Code Playgroud)
没关系,但QA强迫我通过url参数禁用身份验证的可能性.目前,对以下URL的POST也将进行身份验证:
https://example.com/foo?login=admin&password=password
Run Code Online (Sandbox Code Playgroud)
有没有人知道禁用此选项的技巧?最好带注释.
由于评论,我决定在我的问题中添加更多细节.我的弹簧安全配置spring-security.我有
http.usernameParameter("login")
.passwordParameter("password")
(...)
Run Code Online (Sandbox Code Playgroud)
这使得WebSecurityConfigurerAdapter在参数和正文中搜索登录数据.我希望禁用在网址中搜索这些参数.
chi*_*mmi 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
);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑 Haim Raman提出了另一种 使用现有过滤器而不是引入新过滤器的解决方案.只有我建议覆盖obtainUsername()而obtainPassword()不是attemptAuthentication().
我想提出一个基于Spring-security rater的替代方案,然后根据chimmi建议的解决方法.
这个答案为xenteros在 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!");
}
}
}
Run Code Online (Sandbox Code Playgroud)
您需要将现有实现替换为现有实现(请参阅此处的 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;
}
}
Run Code Online (Sandbox Code Playgroud)
优点:它基于弹簧安全性和灵活变化.
缺点:不幸的是我发现Spring Java Config很难设置和阅读
编辑:我接受了chimmi评论并覆盖了gainUsername和obtainPassword
你可以在github中找到源代码.
就像我所提到的那样,尽我所知和直觉,适当的解决方案是使用注释@RequestMapping(value="/login", method="RequestMethod.POST").然后,无论用户使用URL传递什么参数,URL和URI都将始终默认为/ login.这就是记录器将记录的内容.不是用户名和密码对,而是 "http://localhost:8080/login"或者您的端口是什么.
你可以通过修改UsernamePasswordAuthenticationFilter's 来实现这一点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()
...
}
}
Run Code Online (Sandbox Code Playgroud)
注意:以下要求不会阻止发出GET请求(从而泄露凭据).用户界面确实不会发生这种情况.
没关系,但QA强迫我通过url参数禁用身份验证的可能性.
| 归档时间: |
|
| 查看次数: |
3196 次 |
| 最近记录: |