22
votes

Spring Security documentation says:

"When you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection."


What if my service is going to be used by both "browser" and "non-browser" clients such as third party external services, does Spring Security provide a way to disable CSRF exclusively for certain type of clients?

3
I would just put a flash program in a browser page, say I'm a non-browser client, and attack the user when they have no CSRF protection.Neil McGuigan
@NeilMcGuigan I am disabling CSRF for trusted clients only, that trust I am establishing thru X509 and SSL/TLS.Himalay Majumdar

3 Answers

9
votes

I am sure there is a way to do this in Spring Security XML, but since I am using Java Config, here is my solution.

 @Configuration
 @EnableWebSecurity
 public class SecurityConfig {

    @Configuration
    @Order(1)
    public static class SoapApiConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/soap/**")
                .csrf().disable()
                .httpBasic();
        }
    }


    @Configuration
    public static class WebApiConfigurationAdapter extends WebSecurityConfigurerAdapter {

        protected void configure(HttpSecurity http) throws Exception {
            http        
                .formLogin()
                    .loginProcessingUrl("/authentication")
                    .usernameParameter("j_username")
                    .passwordParameter("j_password").permitAll()
                    .and()
                .csrf().disable()

        }
     }
}
5
votes

IMHO, there is nothing like that out of the box. What I would do in your case, is to have a hierarchy of URL for example rooted at /api that would be exempt of csrf. It is easy to configure. In the XML config, you have a normal <http> block including <csrf/>, you just duplicate it and modify the first block like that

<http pattern="/api/**">
    ...
    <!-- csrf -->
</http>

As it is first, it will be triggered for any request to /api hierachy without using csrf, and all other requests will use it.

In the normal part of the application, you never use the /api/** url, and reserve them to non-browser usages.

Then in your controllers, you map them to both their normal url and a copy under /api :

@Controller
@RequestMapping({ "/rootcontrollerurl", "/api/rootcontrollerurl"})
class XController {
    @RequestMapping(value = "/request_part_url", ...)
    public ModelAndView method() {
        ...
    }
}

(of course, rootcontrollerurl and request_part_url may be blank ...)

But you must analyze the security implication of allowing non csrf controlled requests, and eventually exclude controllers from the /api hierarchy.

1
votes

Here is what I used to disable the CSRF protection on an specific endpoint on your appconfig-security.xml add a node with the information of your pattern like the following example:

<http security="none" pattern="/sku/*"/>
<http security="none" pattern="/sku/*/*"/>
<http security="none" pattern="/sku"/>

Just keep in mind the order is important if you are going to use map all request using the symbol '*' goes first.