I have asked to implement CSRF prevent attacking on java server application. It's an application that serves a lot of web REST API services. I looked at many guides and searched here on stack, but still have some concerns. I understand that for GET requests is not needed.
So, correct me if i'm wrong.
- Browser send request for the first time to get CSRF token for session that about 30 minutes
- Then Browser puts this token into script and sends to Back-End.
This is my filter.
public class ValidateCSRFToken implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(ValidateCSRFToken.class);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
// Spring put the CSRF token in session attribute "_csrf"
CsrfToken csrfToken = (CsrfToken) httpServletRequest.getAttribute("_csrf");
// Send the cookie only if the token has changed
String actualToken = httpServletRequest.getHeader("X-CSRF-TOKEN");
if (!StringUtils.isEmpty(csrfToken)) {
LOGGER.info("CSRF token " + csrfToken.getToken());
}
if (!StringUtils.isEmpty(actualToken)) {
LOGGER.info("X-CSRF-TOKEN " + actualToken);
}
if (actualToken == null || !actualToken.equals(csrfToken.getToken())) {
String pCookieName = "CSRF-TOKEN";
Cookie cookie = new Cookie(pCookieName, csrfToken.getToken());
cookie.setMaxAge(-1);
cookie.setHttpOnly(false);
cookie.setPath("/");
httpServletResponse.addCookie(cookie);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
This is my WebSecurity:
//Start chain for restricting access.
http.addFilterAfter(new ValidateCSRFToken(), CsrfFilter.class)
.authorizeRequests()
//The following paths…
.antMatchers("**")
// …are accessible to all users (authenticated or not).
.permitAll()
.antMatchers( "/actuator/**").permitAll()
// All remaining paths…
.anyRequest()
// ...require user to at least be authenticated
.authenticated()
.and()// And if a user needs to be authenticated...
.formLogin()
// ...redirect them to /username`
.loginPage("/username")
.and()
.logout().clearAuthentication(true).invalidateHttpSession(true).deleteCookies("JSESSIONID")
.and()
// If user isn't authorised to access a path...
.exceptionHandling()
// ...redirect them to /403
.accessDeniedPage("/403")
.and()
.cors()
.and()
.csrf();
// .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());;
So, the questions are:
- How to validate it and not to pass through filter chain?
- How to do that for the first time when browser comes with the first request, in other words, how do we know that this request belongs to browser and not to attackers?