Understanding CORS
CORS or Cross Origin Resource Sharing is an http mechanism to let a user gain access to resources located on a domain other that the one the site lives on by using some additional headers. So for example lets say your app located on http://test1.domain.com
needs to make a REST call to an api located on http://test2.domain.com/some/awesome/endpoint
.
Now By default a browser wouldn't allow such a request. This is done for http security reasons. What that means is a browser wouldn't allow a request made from within a script on a webpage to access any HTTP resources located on a domain other than the one site was originally loaded from. For example both XMLHttpRequest and the Fetch API follow same-origin policy. Thats where CORS comes in. CORS facilitates this behavior by first validating test2.domain.com
using some special headers
Headers
The headers that relate to CORS are :
Request Headers
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
Response Headers
- Access-Control-Allow-Origin
- Access-Control-Allow-Credentials
- Access-Control-Expose-Headers
- Access-Control-Max-Age
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
Functional Overview
The way CORS works is :
1) Browser encounters an resquest being made to test2.domain.com
2) It examines if the request is GET or HEAD. If it is, it looks for any custom HTTP Headers. If it fnds any, it moves on to step 3 otherwise it proceeds to make the actual request, i.e step
3) Browser then makes an OPTIONS request test2.domain.com
using following headers :
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
4) test2.domain.com
must now respond with appropriate Access-Control- headers
5) If appropriate Access-Control- headers are not found in the response of the OPTIONS request, flow terminates with an error.
6) If appropriate Access-Control-* headers are not found in the response of the OPTIONS request, proceed to step 7.
7) Make the actual request.
Implementation
Now if test2.domain.com
, CORS Compatible
is an api gateway, we can achieve this by enabling CORS in gateway. However if you find yourself in a situation where the domain or even gateway doesn't supports this functionality out of box, don't worry, there's still a way.
You can have a iRule setup in F5 to insert these custom headers to make test2.domain.com
, CORS Compatible
when HTTP_REQUEST priority 200 {
unset -nocomplain cors_origin
if { ( [HTTP::header Origin] contains "test1.domain.com" ) } {
if { ( [HTTP::method] equals "OPTIONS" ) and ( [HTTP::header exists "Access-Control-Request-Method"] ) } {
# CORS preflight request - return response immediately
HTTP::respond 200 "Access-Control-Allow-Origin" [HTTP::header "Origin"] \
"Access-Control-Allow-Methods" "POST, GET, OPTIONS" \
"Access-Control-Allow-Headers" [HTTP::header "Access-Control-Request-Headers"] \
"Access-Control-Max-Age" "86400" \
"Access-Control-Allow-Credentials" "true"
} else {
# CORS GET/POST requests - set cors_origin variable
set cors_origin [HTTP::header "Origin"]
log local0. "Requested hostname: [HTTP::host] from IP: [IP::local_addr]"
}
}
}
when HTTP_RESPONSE {
# CORS GET/POST response - check cors_origin variable set in request
if { [info exists cors_origin] } {
HTTP::header remove Access-Control-Allow-Origin
HTTP::header remove Access-Control-Allow-Credentials
HTTP::header remove Vary
HTTP::header insert "Access-Control-Allow-Origin" $cors_origin
HTTP::header insert "Access-Control-Allow-Credentials" "true"
HTTP::header insert "Vary" "Origin"
}
}
That's it.
Special Case
I found a really interesting case, while working with CORS, which I think might be worth mentioning here. The setup was something like this, I had a site hosted at domain_a
. It needed a resource hosted at domain_b
. Now domain_b
being an API gateway, I enabled out-of-box CORS functionality on gateway and thought that was it. What I found was that all calls being made to gateway were going through except one particular call which was a resource on a application hosted on websphere server behind gateway. That call was always erroring out with same old CORS error :
No 'Access-Control-Allow-Origin' header is present on the request resource. Origin 'http://test1.domain.com' is therefore not allowed access.
On looking more closely, what was found that Access-Control-*
headers were missing from response coming back for that resource. Now Websphere comes with its own http server, and turns out that http server was eating up the access control headers. From there it was an easy fix to just fix the http.conf on websphere.
So always make sure to validate if you have any underlying http/web server in your infrastructure, if you ever run into something like this.
Comments
comments powered by Disqus