Using CORS (cross origin resource sharing) you can easily and securely to cross site scripting in webapps - less servers and more integration from apis right in the browser
This was presented during Web Directions South, 2013, Sydney, Australia.
2. Integration in the browser
Lots of services, microservices
Everything has an API
JSON == lingua franca
Why have servers that are just text pumps:
Integrate into new apps in the browser
Friday, 25 October 13
9. JSON-P
Add “padding”.
JSON P: take pure json, make it a function call - then
eval it in the browser.
Same Origin Policy doesn’t apply to resource loading
(script tags)
Friday, 25 October 13
11. JSON-P
JSON: { “foo” : 42 }
JSONP: callback({ “foo” : 42 });
Widely supported (both by servers and of course
jquery & co make it transparent)
Friday, 25 October 13
14. JSON-P
What it is really doing: creating script tags, and
making your browser “eval” the lot. Each time, each
request.
Don’t think too hard about it...
Friday, 25 October 13
15. JSON-P
Really misses the “spirit” of same-origin.
Security holes: any script you bring in has access to
your data/dom/private parts.
How secure is server serving up json-p?
Friday, 25 October 13
16. JSON-P
Also, JSON is not Javascript
JSON can be safely read - no eval
JSON-P only eval
JSONP is GET only
Friday, 25 October 13
20. CORS
Trivial to consume: plain web calls, direct.
Complexity: on the server/config side.
Browser support: complete(ish):
http://enable-cors.org/
All verbs, all data types
Friday, 25 October 13
21. CORS - client side ex.
$.ajax({
dataType : "json",
xhrFields: {
withCredentials: true
}
...
});
Friday, 25 October 13
22. How it works
Most work is between browser and server, via http
headers.
“Pre flight checks”:
Browser passes Origin header to server:
Origin: http://www.example-social-network.com
Server responds (header) saying what is allowed:
Access-Control-Allow-Origin: http://www.example-social-network.com
Friday, 25 October 13
23. How it works
browser
server
http OPTIONS (Origin: http://boo.com)
Access-Control-Allow.... etc
preflight
direct http GET /POST (as allowed by Access headers)
...
Friday, 25 October 13
your
app
24. How it works
“Pre flight checks”:
Performed by browser, opaque to client app.
Browser enforces. You don’t see them.
Uses “OPTION” http verb.
Friday, 25 October 13
25. Security Theatre?
“Pre flight checks”:
Can be just an annoyance.
Access-Control-Allow-Origin: *
Downside: allows any script with right creds to pull
data from you (do you want this? Think, as always)
Friday, 25 October 13
26. Common pattern
Access-Control-Allow-Origin: $origin-from-request
The returned value is really echoing back what Origin
was - checked off against a whitelist:
Server needs to know whitelist, how to check, return
value dynamically.
Not a static web server config. SAD FACE.
Friday, 25 October 13
27. 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...
(it isn’t hard, just not as easy as it should be)
http://stackoverflow.com/questions/7067966/how-to-allowcors-in-express-nodejs
Friday, 25 October 13
28. 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
(lists always comma separated)
Friday, 25 October 13
29. Authorization
You can use per request tokens, eg OAuth
OpenID and OAuth based sessions will work
(browser has done redirect “dance” - AccessControl-Allow-Credentials: true -- needed to ensure
cookies/auth info flows with requests)
Friday, 25 October 13
31. Debugging
Pesky pre-flight checks are often opaque - may
show up as “cancelled” requests without a reason.
Use chrome://net-internals/#events
Friday, 25 October 13
32. Debugging
Following screen cap shows it working...
note the match between Origin and Access-control if you don’t see those headers in response something is wrong.
Friday, 25 October 13
35. Debugging
t=1374052796709 [st=262]
t=1374052796709 [st=262]
t=1374052796709 [st=262]
+URL_REQUEST_BLOCKED_ON_DELEGATE
CANCELLED
-URL_REQUEST_START_JOB
--> net_error = -3 (ERR_ABORTED)
[dt=0]
This is it failing: look for “cancelled”.
Could be due to incorrect headers returned, or
perhaps Authorization failures (cookies, session etc)
Friday, 25 October 13
36. My 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
INCLUDE PORTS IN Access-Control-Allow-Origin!!
Friday, 25 October 13
37. Example (express)
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
node and express js:
http://enable-cors.org/server_expressjs.html
Friday, 25 October 13
38. Example (rack/ruby)
gem install rack-cors
...
in config/application.rb:
...
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
https://github.com/cyu/rack-cors
Friday, 25 October 13