1

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.

  1. Browser send request for the first time to get CSRF token for session that about 30 minutes
  2. 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:

  1. How to validate it and not to pass through filter chain?
  2. 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?
9
  • 2
    you dont need to validate it yourself, spring security already has a CSRF filter in place, so you can remove the filter. Second, the token is only needed to be sent when you mutate something on the server, so during POST, PUT, UPDATE. To answer your second question: you dont, thats why you have other security like CORS, user logins, tokens, session cookies, passwords etc. Never trust the client, or the request. You always validate "who are you (authentication), are you allowed to do what you want to do? (authorization)" Commented Oct 6, 2021 at 23:27
  • read the chapter on CSRF in spring security and how to implement it. Read OWASP on CSRF attacks to understand WHAT you are protecting yourself from cheatsheetseries.owasp.org/cheatsheets/… Commented Oct 6, 2021 at 23:30
  • then read the spring security reference chapter on CSRF docs.spring.io/spring-security/site/docs/current/reference/… Commented Oct 6, 2021 at 23:37
  • Let's say for the first time browser sends request via Login API to back-end. Then this request still without the CSRF token(or no??) and Spring generates the token , but allows to request to get the logic of login. So, why bowser when it's up , just sends only request to get token without any doing logic, and user even doesn't do nothing in borwser. WE are sure that the token is generated and sent back. Then when user wants to login , so browser has already token in session and puts in request. In other words, create dedicated service only to generate the token. is it good? Commented Oct 7, 2021 at 6:35
  • What i want to say in previous comment, that not pass to inside the logic of application without the token for the first time. So, yes i need a filter to prevent it and return only the token. Commented Oct 7, 2021 at 6:39

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes , i don't do any changes on DB with GET requests. I've checked it. Then anyway i need to implement this logic to identify where to give this token , like "if method doesn't equal GET, then give token"? This implementation should be done?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.