I'm developing an android app and I'm using Spring as a REST backend.
Every time I try to make post request to the server I get a 403 response with this message "Expected CSRF token not found. Has your session expired?".
I tried to disable csrf in the application.properties and with my own WebSecurityConfigurerAdapter implementation but to no avail.
Did I miss something ?
Try this :
.invalidateHttpSession(true)
.and()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.csrf()//Disabled CSRF protection
.disable();
Add this on your logoutSuccessHandler(...)
There are different ways to disable CSRF in Spring boot , by default in spring boot is enable
1. By Java Configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
2. By Application.yml
security.enable-csrf: false
Related
I have been trying to configure Spring Boot security in order to allow some urls without requiring an authentication and not allowing any other requests without an authentication. I am having trouble achieving this.
As per my understanding, anyRequest().authenticated() requires previously declared antMatchers to require authentication.
How is it possible to achieve my requirement.
My Http Security configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers(HttpMethod.POST,SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET,banner_top_url).permitAll()
.antMatchers(HttpMethod.GET,banner_bottom_url).permitAll()
.antMatchers(HttpMethod.GET,javascript_url).permitAll()
.antMatchers(HttpMethod.GET,stylesheet_url).permitAll()
.antMatchers(HttpMethod.GET,photos_url).permitAll()
.antMatchers(HttpMethod.GET,transformed_photos_url).permitAll()
.antMatchers(HttpMethod.GET,preview_url).permitAll()
.antMatchers(HttpMethod.GET, "/", "/**/*.html", "/static/favicon.ico", "/**/*.js", "/**/*.js.map", "/**/*.css", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.ttf", "/**/*.json", "/**/*.woff", "/**/*.woff2", "/**/*.eot", "/**/*.svg").permitAll()// allows static content from resource folder
.antMatchers("/error").permitAll() // By default Security framework disables error pages (Unauthrorized)
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().addFilterBefore(jwtExceptionHandler,CorsFilter.class)
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().formLogin().disable();
}
I assume that the below urls must be granted access without authentication.
SIGN_UP_URL
banner_top_url
banner_bottom_url
javascript_url
stylesheet_url
photos_url
transformed_photos_url
preview_url
The problem is this line : .anyRequest().authenticated()
If I remove it, then all the endpoints within the REST interface becomes available without authentication which I do not want.
Why aren't you excluding the static resource files globally via web.ignoring?
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
By default, Spring-security allows to pass everything. You have to tell Spring what can pass and what cannot pass. By removing anyRequest().authenticated you are telling to spring that everything that matches the patterns you mentioned are allowed to go and with the rest do what you do by default, that means, proceed. Here you are Spring Security doc: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-httpsecurity
I have found that Spring-Working as intended. That being said,any antMAtchers will match the requestPath and not the resourcePath. An example is provided below.
*localhost:8080/image.jpg*
points at the root of the application which is src/main/resources/static/image.jpg
Now why is static used as a resource handler, that is because in the staticResourceConfiguration.java class I had the following lines
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
I have the following code
http.authorizeRequests()
.antMatchers("/users/login","/token/refresh").permitAll()
.anyRequest().authenticated()
.and()
.addFilterAfter(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
And I thought it mean do not filter requests that match /users/login or /token/refresh, but filter any request that doesn't match that.
But it still filters on /users/login.
The way I solved in an old project is requiring auth on every endpoint
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterAfter(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
and ignoring security on the desired endpoints
public void configure(WebSecurity web) {
web.ignoring().antMatchers(HttpMethod.POST, "/users/login");
}
Try this.
.antMatchers("/users/login").permitAll()
.antMatchers("/token/refresh").permitAll()
csrf is enabled by Spring Security automatically. Try disabling it.
http.csrf().disable().authorizeRequests().antMatchers("/users/login","/token/refresh").permitAll().anyRequest().authenticated().and().addFilterAfter(new JWTAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class)
Our application is using spring security to secure the application,i just added one rest controller which supporting spring oauth security, for oauth token validation, will be called by some other application following are my controller code
#RestController
#EnableResourceServer
public class Controller extends BaseRestController{
#RequestMapping(value="/api/v1/public/insertData", method=RequestMethod.POST)
ResponseEntity<?> insertTPQueueData(TitleProcurementQueue queue,Authentication authentication) {
return null;
}
}
after adding spring oauth security i am getting following error for my other controller using spring security
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
Please help
When you put security in your project spring implement some filters, like Cors, basic auth etc..
So you need to tell spring how apply security in your resources.
enter link description here
need to create a class with #EnableWebSecurity
and configure like this:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
I developed an application with spring boot, which was working fine. There is a restful controller. I tried to add spring security to some of the pages.
The rest controller's endpoint is
/api/greetings
I configured the security settings in the class below.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home","/api/greetings").permitAll()
//.antMatchers("/api/greetings","").permitAll()//can't do this
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
Now, when I tried accessing the Rest endpoint, from a Rest-client(Postman), only the GET method is accessible and i am getting 403 Forbidden response if I try to POST, PUT or DELETE.
{
"timestamp": 1467223888525,
"status": 403,
"error": "Forbidden",
"message": "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.",
"path": "/api/greetings/2"
}
How do i solve this issue. I am new to Spring Security things.
UPDATE Answer
If you're using Spring security 4, you can disable specific routes easily
http.csrf().ignoringAntMatchers("/nocsrf","/ignore/startswith/**")
If not, you can enable/disable CSRF on specific routes using requireCsrfProtectionMatcher
http.csrf().requireCsrfProtectionMatcher(new RequestMatcher() {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
private RegexRequestMatcher apiMatcher = new RegexRequestMatcher("/v[0-9]*/.*", null);
#Override
public boolean matches(HttpServletRequest request) {
// No CSRF due to allowedMethod
if(allowedMethods.matcher(request.getMethod()).matches())
return false;
// No CSRF due to api call
if(apiMatcher.matches(request))
return false;
// CSRF for everything else that is not an API call or an allowedMethod
return true;
}
});
ORIGINAL Answer
You got an error because CSRF handling is 'on' by default with Spring Security.
You can disabled it by adding http.csrf().disable();.
But really, would you leave your application unsecured? I invite you to read this article to protect your application against CSRF, even if your application is based on REST service and not form submission.
I'm trying to implement an Angular app using this tutorial: https://spring.io/guides/tutorials/spring-security-and-angular-js/
Logging in works and performing subsequent HTTP calls works, too. Angular successfully appends the CSRF token and Spring successfully parses it. Assuming the token is foo, the requests will contain these headers:
Cookie: JSESSIONID=...; XSRF-TOKEN=foo
X-XSRF-TOKEN: foo
Now, when trying to log out with
$http.post('logout', {}), Angular will use exactly the same headers. However, Spring answers with a 403:
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
This is what my security configuration looks like:
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated().and()
.logout().and()
.addFilterBefore(new CsrfHeaderFilter(), CsrfFilter.class);
}
CsrfHeaderFilter is the class explained in the tutorial (which apparently works for every other request).
I realize it's 2 months late, but I was following the exact same guide today and this unanswered post keeps on popping up so here's the solution.
Basically, you were missing the csrfTokenRepository() configuration in the HttpSecurity configurer.
Spring CsrfTokenRepository expects the header "X-CSRF-TOKEN" but Angular sends the token in a header called "X-XSRF-TOKEN" so the guide recommended you setup an instance of CsrfTokenRepository which expects the Angular default header "X-XSRF-TOKEN":
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated().and()
.logout()
.and()
//This is the first part you were missing
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterBefore(new CsrfHeaderFilter(), CsrfFilter.class);
}
#Bean
public CsrfTokenRepository csrfTokenRepository(){
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
// This is the second part you were missing
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}