Same Origin Policy is an imporatnt concept of web application security model but while biulding RESTful Api’s you may need some work arounds to tackle it, some of them are mentioned as under:
- Integration Middleware
Here one server acts as proxy for other servers, issue with this approach is that there are more servers to maintain, and there is more latency.
- jsonp
jsonp JavaScript Object Notation with padding. Take a pure json, make it function call then eval in the browser.Note same origin policy doesnt apply to resource loading(script tags), lets see an example
json:{'price':42}
,jsonp:callback({'price':42});
1
2
3
4
5
6
7
8
9
10
11
12
$.ajax({
...
dataType:"json",
...
});
$.ajax({
...
dataType:"jsonp",
jsonp:"jsonp",
...
});
what it does is create a script tag and making your browser “eval” the lot. Each time each request comes in.Some known security holes are there, any script you bring in has access to your data/dom/ private parts. Moreover Jsonp is GET only and for our usual RESTful Api’s we need other http verbs too.
- CORS(Cross Origin Resource Sharing) CORS allows servers to specify who, what can access endpoint directly. It uses plain json , and all http verbs: PUT,DELETE, etc are available
It is trivial to consume, has plain web calls , and is direct although there is some complexity on the server/config side.There is good browser support for details check here All verbs, all data types
- Client Side Example
1
2
3
4
5
$.ajax ({
dataType:"json",
xhrFields:{withCredentials:true} //pass cookie, credentials
...
});
Most of the work happens between browser and server, using http headers called “pre flight checks”.The browser passes origin header to server e.g
Origin:http://www.example-social-network.com
, server responds(header) saying what is allowed Access-Control-Allow-Origin :http://www.example-social-network.com
“Pre flight checks” are performed by browser, opaque to client app.Browser enforces.you dont see them, browser Uses “OPTION” http verb.Can be anoyance if we use Access-Control-Allow-Origin:*
. Downside of approach is that it allows any script with right credentials to pull data from you.
- Common pattern:
Access-Control-Allow-Origin:$origin-from-request
The returned value is really echoing back what Origin was checked off against a whitelist
- Middleware
All app server environments have a way to do the right thing with CORS headers: rack-cors:ruby, Servlet-filter: java, Node :express middleware etc.
Note that authorization has to be handled by your app.
- Other CORS headers
Access-Control-Allow-Headers
(headers to be included in requests)
Access-Control-Allow-Methods:GET, PUT , POST , DELETE
etc
Access-Control-Allow-Credentials:boolean
- Minimal setup
Access-Control-Allow-Methods:GET,POST,PUT,DELETE
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:$ORIGIN
$ORIGIN = if (inWhitelist(requestOriginHeader))return requestOriginHeader
-
Implemented Server Side Code (nginx):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# pass requests for dynamic content to rails/turbogears/zope, et al
location / {
...
if ($http_origin ~* (https://abc.com|https://abc.com|http://xyz.com|http://somerandomsite.org|http://secondrandomsite.com|http://somedomain.com)) {
set $cors "true";
}
# Handle CORS
#set $cors "true";
# if it's a GET or POST, set the standard CORS responses header
if ($cors = "true") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type';
}
...
}
-
Implemented Client Side Code (ajax)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
server_name = "mytestsever.com";
//GET
ajaxOptsCrossOrigin = {
xhrFields: {withCredentials: true}, //adds cookies, credentials
url: "https://"+server_name+"/get_link/",
dataType: 'json',
crossDomain: true,
data: data_vals,
success: function(resp){
//do something on success
},
};
jQuery.ajax(ajaxOptsCrossOrigin);
//POST
ajaxOpts = {
url:"https://"+server_name+"/post_link/",
crossDomain:true,
xhrFields: {withCredentials:true},
type:'POST',
data: jQuery('#some_form').serialize(),
dataType:'json',
success: {
//do something
},
error: {
//do something
},
};
jQuery.ajax(ajaxOpts);
For django one can skip all this an simple use django-cors-headers plugin or directly add the headers in the view which responds to the urls in the ajax calls.
Learn more about CORS here: wikipedia, html5rocks, enable-cors.org, Michael Neale. Thanks for Reading