我正在使用 Spring 4.3.12.RELEASE 版本,AngularJS 1.4.8。我试图阻止对应用程序的 CSRF 攻击。
@Configuration
@Order(2)
public static class SecurityConfig extends WebSecurityConfigurerAdapter {
String[] pathsToRemoveAuthorizaton = {
"/mobile/**",
"/logout",
"/j_spring_security_logout",
"/login",
};
private final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
@Override
public void configure(HttpSecurity http) throws Exception {
logger.info("http configure");
http.antMatcher("/**").authorizeRequests().antMatchers(pathsToRemoveAuthorizaton).permitAll()
.antMatchers("/**").authenticated()
.and().formLogin().loginPage("/login")
.usernameParameter("employeeId").passwordParameter("password")
.successForwardUrl("/dashboard").defaultSuccessUrl("/dashboard", true)
.successHandler(customAuthenticationSuccessHandler()).loginProcessingUrl("/j_spring_security_check")
.and().logout().logoutSuccessUrl("/logout").logoutUrl("/j_spring_security_logout")
.logoutSuccessHandler(customLogoutSuccessHandler()).permitAll().invalidateHttpSession(true)
.deleteCookies("JSESSIONID").and().sessionManagement().sessionFixation().newSession()
.maximumSessions(1).maxSessionsPreventsLogin(true).and()
.sessionCreationPolicy(SessionCreationPolicy.NEVER).invalidSessionUrl("/logout").and()
.exceptionHandling().accessDeniedPage("/logout");
// http.csrf().csrfTokenRepository(csrfTokenRepository()).and()
// .addFilterAfter(new StatelessCSRFFilter(), CsrfFilter.class);
http.csrf().csrfTokenRepository(csrfTokenRepository());
// http.csrf().disable();
// http.csrf().ignoringAntMatchers("/mobile/**");
http.authorizeRequests().anyRequest().authenticated();
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
@Bean
public AuthenticationSuccessHandler customAuthenticationSuccessHandler() {
return new CustomAuthenticationSuccessHandler();
}
@Bean
public LogoutSuccessHandler customLogoutSuccessHandler() {
return new CustomLogoutSuccessHandler();
}
}
下面是我的角度服务代码
govtPMS.service('Interceptor', function($q, $location, $rootScope, pinesNotifications, Auth) {
return {
request: function(config) {
config.headers.Authorization = 'Bearer '+$rootScope.authToken;
// document.cookie = 'CSRF-TOKEN=' + $rootScope.generateKey;
return config;
},
requestError: function (rejection) {
return $q.reject(rejection);
},
response: function(res) {
if(res.status === 200 || res.status === 201){
if(res.data.response !== undefined){
if(res.data.status === 1 || res.data.status === 3 || res.data.status === 2) {
pinesNotifications.notify({
'title': 'Success',
'text': res.data.message,
'type': 'success',
'delay': 5000
});
}
else if(res.data.status === 5) {
pinesNotifications.notify({
'title': 'Warning',
'text': res.data.message,
'type': 'warning',
'delay': 5000
});
}
}
}
return res || $q.when(res);
},
responseError: function(error) {
return $q.reject(error);
}
};
}).config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';
$httpProvider.defaults.xsrfCookieName = 'CSRF-TOKEN';
$httpProvider.interceptors.push('Interceptor');
}])
我仍然无法看到 CSRF 令牌标头以及请求。
在这个应用程序中,我们使用了 3 个 jsp 页面 - login.jsp、logout.jsp 和dashboard.jsp 角度范围在dashboard.jsp 中定义,因此登录和注销超出了AngularJS 的范围。我也从这个和这个例子中尝试了无状态的方式,其中 angular 正在生成一个 UUID 并附加 cookie 和请求标头,下面的过滤器做得很好。直到注销攻击。在此攻击中,攻击者试图成功注销用户,因为要从应用程序中注销,我们只是使用了 href。
<li><a href="j_spring_security_logout" ><i class="fa fa-sign-out"></i><span>Logout</span></a></li>
现在,由于它的注销没有角度,所以 angularjs 拦截器无法在此处附加 UUID。自上周以来,我一直在为此苦苦挣扎,任何帮助将不胜感激。
无状态CSRFFilter.java
package com.leadwinner.sms.config.filters;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.web.filter.OncePerRequestFilter;
public class StatelessCSRFFilter extends OncePerRequestFilter {
private static final String CSRF_TOKEN = "CSRF-TOKEN";
private static final String X_CSRF_TOKEN = "X-CSRF-TOKEN";
private final AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
List<String> excludedUrls = new ArrayList<>();
excludedUrls.add("/resources");
excludedUrls.add("/j_spring_security_check");
excludedUrls.add("/j_spring_security_logout");
excludedUrls.add("/login");
excludedUrls.add("/logout");
excludedUrls.add("/mobile");
excludedUrls.add("/migrate");
excludedUrls.add("/dashboard");
String path = request.getServletPath();
System.out.println(path);
AtomicBoolean ignoreUrl = new AtomicBoolean(false);
excludedUrls.forEach(url -> {
if (request.getServletPath().startsWith(url.toLowerCase()) || request.getServletPath().equals("/")) {
ignoreUrl.set(true);
}
});
if (!ignoreUrl.get()) {
final String csrfTokenValue = request.getHeader(X_CSRF_TOKEN);
final Cookie[] cookies = request.getCookies();
System.out.println("**************************************************");
System.out.println("--------------------------------------------------");
String csrfCookieValue = null;
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(CSRF_TOKEN)) {
csrfCookieValue = cookie.getValue();
}
}
}
System.out.println("csrfTokenValue = "+csrfTokenValue);
System.out.println("csrfCookieValue = "+csrfCookieValue);
System.out.println("--------------------------------------------------");
System.out.println("**************************************************");
if (csrfTokenValue == null || !csrfTokenValue.equals(csrfCookieValue)) {
accessDeniedHandler.handle(request, response, new AccessDeniedException(
"Missing or non-matching CSRF-token"));
return;
}
}
filterChain.doFilter(request, response);
}
}