Reputation: 159
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.
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:
Upvotes: 1
Views: 9928
Reputation: 102988
I understand that for GET requests is not needed.
The point of it is to ensure anything the user does that has any side effect, is actually an intended interaction. Now, GET
requests should have no side effects at all, but if you messed that up and some GET requests do have side effects, then you either need to fix that, or if you can't, then your GET requests also need CSRF protection. Which is a bit tricky, it's not entirely a good idea to spam the token into a URL (which is what would happen).
For example, if just hitting https://yourserver.com/commands/deletePost?p=18
deletes the article with unid 18 from the database if you're logged in as admin, I can make a site with:
<a href="https://yourserver.com/commands/deletePost?p=18">Click to see cute kittens!</a>
and post it. Then I just wait for your to click it and voila. Post is gone. That's what CSRF is about.
So, go through the entire code base. Is there any place in it where any GET request causes state changes (files created or wiped, database INSERT or UPDATE or DELETE commands, APIs used to cause state changes such as posting stuff on twitter or whatnot - that sort of thing). Fix that code and ensure they simply do not allow that and only work on POST/PUT.
Then add CSRF to all those POSTs/PUTs (or, better yet, just to all POSTs; consider any POST without CSRF tokens as if the user wasn't logged in).
Note that many web framework kits already have CSRF protection systems in place, including Spring Security.
Upvotes: 5