0

In am working on a Spring Boot (1.3.2) application which just serves Spring MVC REST controllers that are consumed by a JavaScript single page app (deployed standalone, not inside the boot jar). The setup uses Spring Security, Spring Session and has CSRF protection enabled.

This works as expected for the JavaScript client. A login is done by a GET call with Basic Auth provided, the backend creates a session, returns a cookie and also provides the CSRF token in the response according to this blog post at https://spring.io/guides/tutorials/spring-security-and-angular-js/ (except that the custom filter is way more behind in the chain to obtain the correct token after the SessionManagementFilter - which is not that relevant for this question I think).

Until here, everything works as intended pretty elegantly without any workarounds.

Now we also want to expose some of the interfaces for mobile/cli clients. These clients should be able to access a subset of the interfaces via Basic Auth. So the goal is to allow non-readonly calls (POST, PUT, DELETE) for these clients by just providing the credentials via Basic Auth. As they provide the credentials in their request, it is not neccessary for them to provide a CSRF token.

So my first idea was to look for some way to conditionally skip some filters (the csrf) if there was a successful authentication by the provided Basic Auth. It seems that the existing filters are not meant to be used in that way and this would also somehow violate the concept of Spring Security.

I then thought to have found a solution by using the concept explained in the Spring Security docs (http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#multiple-httpsecurity) that uses separate WebSecurityConfigurerAdapters as also described in Spring Boot web app w/ both session + CSRF & stateless Basic Auth w/o CSRF or How can I configure spring security for multiple servlets?

So currently I have two WebSecurityConfigurerAdapters with different Orders and disjunct request matchers, both overriding configure(AuthenticationManagerBuilder auth) and configure(HttpSecurity http). I therefore aliased the relevant REST controllers by using @RequestMapping({"/things", "/aliased/things"}) to be able to get separate security filter chains.

This works in a way that depending on the Path ("things" or "aliased/things") the according filter chain is used. But somehow this setup is still corrupt as I now can do a "login" on the regular path, which creates a session and with this session, I now can also call one of the second filter chain's path which now results in a correct authentication (probably due to the SecurityContextPersistenceFilter) which authenticates me and allows non CSRF-protected calls to the interfaces on the chain which should be used by the mobile clients only.

This seems not to be the way to handle such a case. I am interested in finding hints how to handle that requirement - which in my opinion should be some common use case. Probably I was running way to far in the wrong direction with my experiments.

Community
  • 1
  • 1
Andreas Jägle
  • 11,632
  • 3
  • 31
  • 31
  • Do you have a way to guarantee you know that the request came from the mobile client vs a browser? – Rob Winch Feb 24 '16 at 20:36
  • I think the best way to distinguish it, is that a call from mobile will always have **valid** Basic Auth headers set (so credentials were verified as correct) and doesn't use a cookie. It would be a huge security breach to allow a request that was authenticated via cookie to pass the "mobile" filter chain without csrf protection. This was equivalent to disabling csrf completely. Is using different chains really the way to do it? – Andreas Jägle Feb 25 '16 at 08:44
  • 1
    The problem is that CSRF attacks can be performed if basic authentication is used. This means if you disable CSRF protection for your mobile clients, your browser based users are also vulnerable. See http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#csrf-and-stateless-browser-applications – Rob Winch Feb 25 '16 at 21:04
  • Thanks for this hint. We disabled the WWW-Authenticate header to perform the authentication using Basic Auth via JavaScript. Doing this is not a requirement, we could also switch to a special controller for handling the login. – Andreas Jägle Feb 26 '16 at 08:50
  • Do you know a good way to generally approach this csrf vs. basic auth requirement? I was already thinking about using two different war files... – Andreas Jägle Feb 26 '16 at 08:59

0 Answers0