diff --git a/content/images/cors_flow.png b/content/images/cors_flow.png new file mode 100644 index 0000000..63b8be8 Binary files /dev/null and b/content/images/cors_flow.png differ diff --git a/content/python/cornice-cors.rst b/content/python/cornice-cors.rst new file mode 100644 index 0000000..b9f4db9 --- /dev/null +++ b/content/python/cornice-cors.rst @@ -0,0 +1,254 @@ +Implementing CORS in Cornice +############################ + +:date: 22-01-2013 +:slug: cross-origin-in-cornice +:status: draft + +For security reasons, it's not possible to do cross-domain requests. In other +words, if you have a page served from the domain `lolnet.org`, it will not be +possible for it to get data from `notmyidea.org`. + +Well, it's possible, using tricks and techniques like `JSONP +`_, but that doesn't work all the time (see +`the section below <#how-this-is-different-from-jsonp>`_). I remember myself +doing some simple proxies on my domain server to be able to query other's API. + +Hopefuly, there is a nicer way to do this, namely, "Cross Origin +Resource-Sharing", or `CORS `_. + +You want an icecream? Go ask your dad first. +============================================ + +If you want to use CORS, you need the API you're querying to support it; on the +server side. + +The HTTP server need to answer to the `OPTIONS` verb, and with the appropriate +response headers. + +`OPTIONS` is sent as what the authors of the spec call a "preflight request"; +just before doing a request to the API, the *User-Agent* (the browser most of +the time) asks the permission to the resource, with an `OPTIONS` call. + +The server answers, and tell what is available and what isn't: + +.. image:: |filename|/images/cors_flow.png + :alt: The CORS flow (from the HTML5 CORS tutorial) + +- 1a. The User-Agent, rather than doing the call directly, asks the server, the + API, the permission to do the request. It does so with the following headers: + + - **Access-Control-Request-Headers**, contains the headers the User-Agent + want to access. + - **Access-Control-Request-Method** contains the method the User-Agent want + to access. + +- 1b. The API answers what is authorized: + + - **Access-Control-Allow-Origin** the origin that's accepted. Can be `*` or + the domain name. + - **Access-Control-Allow-Methods** a *list* of allowed methods. This can be + cached. Note than the request asks permission for one method and the + server should return a list of accepted methods. + - **Access-Allow-Headers** a list of allowed headers, for all of the + methods, since this can be cached as well. + +- 2. The User-Agent can do the "normal" request. + + +So, if you want to access the `/icecream` resource, and do a PUT there, you'll +have the following flow:: + + > OPTIONS /icecream + > Access-Control-Request-Methods = PUT + > Origin: notmyidea.org + < Access-Control-Allow-Origin = notmyidea.org + < Access-Control-Allow-Methods = PUT,GET,DELETE + 200 OK + +You can see that we have an `Origin` Header in the request, as well as +a `Access-Control-Request-Methods`. We're here asking if we have the right, as +`notmyidea.org`, to do a `PUT` request on `/icecream`. + +And the server tells us that we can do that, as well as `GET` and `DELETE`. + +I'll not cover all the details of the CORS specification here, but bear in mind +than with CORS, you can control what are the authorized methods, headers, +origins, and if the client is allowed to send authentication information or +not. + + +A word about security +===================== + +CORS is not an answer for every cross-domain call you want to do, because you +need to control the service you want to call. For instance, if you want to +build a feed reader and access the feeds on different domains, you can be +pretty much sure that the servers will not implement CORS, so you'll need to +write a proxy yourself, to provide this. + +Secondly, CORS, if misunderstood, can be unsecure, and cause some security +problems. Because the rules apply when a client want to do a request to +a server, you need to be extra careful about who you're authorizing. + +A CORS uncorrectly-secured server can be accessed by a client very easily, +bypassing the network security. For instance, if a service runs on an intranet, +only available from behind a VPN, and accepts every cross-origin call, then +anyone service javascript files to the browser of an user with access to this +service could make calls there, which is probably not what you want. + + +How this is different from JSONP? +================================= + +You may know the `JSONP `_ protocol. JSONP +Allows to do cross origin, but for a particular use case, and do have some +drawbacks (for instance, it's not possible to do DELETEs or PUTs with JSONP. + +JSONP exploits the fact that's possible to get information from another domain +when you are asking for javascript code, using the `