Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CORS preflight request fails due to a standard header

Tags:

cors

spring

While debugging a CORS issue I am experiencing I've found the following behaviour. Chrome makes the following OPTIONS preflight request (rewritten in CURL by Chrome itself):

curl -v 'https://www.example.com/api/v1/users' -X OPTIONS -H 'Access-Control-Request-Method: POST' -H 'Origin: http://example.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: es-ES,es;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36' -H 'Accept: */*' -H 'Referer: http://example.com/users/new' -H 'Connection: keep-alive' -H 'Access-Control-Request-Headers: accept, x-api-key, content-type' 

The response from the server to this request if the following:

< HTTP/1.1 403 Forbidden < Date: Thu, 21 Jul 2016 14:16:56 GMT * Server Apache/2.4.7 (Ubuntu) is not blacklisted < Server: Apache/2.4.7 (Ubuntu) < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-Frame-Options: SAMEORIGIN < Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH < Content-Length: 20 < Keep-Alive: timeout=5, max=100 < Connection: Keep-Alive 

being the body of the response 'Invalid CORS request'. If I repeat the request removing the header 'Access-Control-Request-Method' (and only that header) the OPTIONS requests succeeds with the following reponse:

< HTTP/1.1 200 OK < Date: Thu, 21 Jul 2016 14:21:27 GMT * Server Apache/2.4.7 (Ubuntu) is not blacklisted < Server: Apache/2.4.7 (Ubuntu) < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-Frame-Options: SAMEORIGIN  < Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with, x-api-key < Access-Control-Max-Age: 60 < Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS < Access-Control-Allow-Origin: * < Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH < Content-Length: 0 < Keep-Alive: timeout=5, max=100 < Connection: Keep-Alive 

However, the offending header is a CORS spec standard header so it should not prevent the request from succeeding, right? Why is this header causing such behaviour?

And how can I tweak the access control headers sent by my server to make the request work when made with Chrome?

By the way, I am using Chrome 36.0, and the server is using Spring Boot, with the CORS headers being managed by Spring.

When the request is made by Firefox (v47.0) the behaviour is different but with an analogue result. Firefox does not even send the preflight request, it directly sends the POST request, which receives as response a 403 Forbidden. However, if I copy the request with the 'Copy as cURL' option, and repeat it from a terminal window, It succeeds and sends the correct CORS headers in the response.

Any idea?

Update: Firefox does send the preflight OPTIONS request (as shown by the Live HTTP headers plugin), but Firebug masks it, so the behaviour in both browsers it exactly the same. In both browsers is the 'Access-control-request-method' header the difference that makes the request fail.

like image 866
joanlofe Avatar asked Jul 21 '16 14:07

joanlofe


People also ask

What is a CORS preflight request?

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers. It is an OPTIONS request, using three HTTP request headers: Access-Control-Request-Method , Access-Control-Request-Headers , and the Origin header.

How do I fix CORS header Access-Control allow Origin missing?

If the server is under your control, add the origin of the requesting site to the set of domains permitted access by adding it to the Access-Control-Allow-Origin header's value. You can also configure a site to allow any site to access it by using the * wildcard. You should only use this for public APIs.


2 Answers

After a lot of struggling, I finally found the problem. I configured a request mapping in Spring to handle OPTIONS traffic, like this:

@RequestMapping(value= "/api/**", method=RequestMethod.OPTIONS) public void corsHeaders(HttpServletResponse response) {     response.addHeader("Access-Control-Allow-Origin", "*");     response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");     response.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");     response.addHeader("Access-Control-Max-Age", "3600"); } 

I did not know that by default Spring uses a default CORS processor, and it seems it was interfering with my request mapping. Deleting my request mapping and adding the @CrossOrigin annotation to the appropriate request mappings solved the problem.

like image 192
joanlofe Avatar answered Sep 20 '22 08:09

joanlofe


i also faced the same issue and find solution for enabling global cors issue in spring boot

@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter {     @Override     public void addCorsMappings(CorsRegistry registry) {         registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")                 .allowedHeaders("*");     } } 

after this , we need to enable CORS in spring security level also, so for this add cors() in your SecurityConfiguration class which extent WebSecurityConfigurerAdapter

 @Override     protected void configure(HttpSecurity httpSecurity) throws Exception {          httpSecurity                 .cors()                 .and()                 .csrf().disable()                 .authorizeRequests()..      } 
like image 32
Om Prakash Sharma Avatar answered Sep 22 '22 08:09

Om Prakash Sharma