Cross-origin resource sharing

Allowing client-side JavaScript AJAX to perform cross-domains requests is a potential security risk. If the JS code that's executed in the client page for your domain tries to call another domain that you don't own, it could potentially run malicious JS code and harm your users.

That is why all browsers in the market have a Same-Origin Policy when an asynchronous call is made. They ensure that the request is made on the same domain.

Beyond security, it is also a good way to prevent someone from using your bandwidth for their web app. For instance, if you provide a few font files on your website, you might not want another website to use them on their page, and use your bandwidth without any control.

However, there are legitimate use cases for wanting to share your resources to other domains, and you can set up rules on your service to allow other domains to reach your resources.

That is what Cross-Origin Resource Sharing (CORS) is all about. When the browser sends an AJAX request to your service, an Origin header is added, and you can control that it is in the list of authorized domains.

If not, the CORS protocol requires that you send back a few headers listing the allowed domains.

There's also a preflight mechanism, where the browser pokes the endpoint via an OPTIONS call to know if the request it wants to make is authorized.

On the client side, you do not have to worry about setting up these mechanisms. The browser makes the decisions for you depending on your requests.

However, on the server side, you need to make sure your endpoints answer to the OPTIONS calls, and you need to decide which domains are allowed to reach your resources. If your service is public, you can authorize all domains with a wildcard. However, for a microservice-based application where you control the client side, you should restrict the domains.

In Flask, you can use Flakon's crossdomain() decorator to add CORS support to an API endpoint. In the following Flask app, the /api/runs.json endpoint can be used by any domain:

    from flask import Flask, jsonify 
from flakon import crossdomain

app = Flask(__name__)

@app.route('/api/runs.json')
@crossdomain()
def _runs():
run1 = {'title': 'Endurance', 'type': 'training'}
run2 = {'title': '10K de chalon', 'type': 'race'}
_data = [run1, run2]
return jsonify(_data)

if __name__ == '__main__':
app.run(port=5002)

When running this app and using cURL to do a GET request, we can see that the ;Access-Control-Allow-Origin:* ;header is added:

$ curl -v http://localhost:5002/api/runs.json 
* Trying localhost...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5002 (#0)
> GET /api/runs.json HTTP/1.1
> Host: localhost:5002
> User-Agent: curl/7.51.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Access-Control-Allow-Origin: *
< Content-Length: 122
< Server: Werkzeug/0.12.1 Python/3.5.2
< Date: Tue, 04 Apr 2017 07:39:48 GMT
<
[
{
"title": "Endurance",
"type": "training"
},
{
"title": "10K de chalon",
"type": "race"
}
]
* Curl_http_done: called premature == 0
* Closing connection 0

This is the default permissive behavior of the crossdomain() decorator, but you can set up fine-grained permissions for each endpoint, and restrict them to specific domains. You can even whitelist allowed HTTP verbs. Flakon also has CORS features at the blueprint level.

For our use case, allowing a domain is good enough. If your JS app is served by a Flask app the runs on localhost:5000 for instance, you can restrict calls to that domain with the following:

    @app.route('/api/runs.json') 
@crossdomain(origins=['http://localhost:5000'])
def _runs():
...

In case a call is made from a browser with origin other than http://localhost:5000, the data is not returned.

Notice that in the case of rejection on a disallowed domain, the decorator returns a 403 response. The CORS protocol does not define what should be the status code when a rejection happens, so, that is an implementation choice.

For an in-depth understanding of CORS, the MDN page is a great resource and can be found at the following link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

In this section, we have looked at how to set up CORS headers in our services to allow cross-domain calls, which are useful in JS apps.

What's still missing to make our JS app fully functional is authentication and authorization.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset