If you already don’t know what is Cross-Origin Resource Sharing(CORS). Please check out the below links:
You may have understood the following:
It’s a mechanism to allow communication of one resource to another resource in a different domain. It sets the header,
which can have the following values -
*, <origin>, null.
To implement CORS simply in flask, there are a bunch of different ways:
To use flask-cors library
flask-cors is a library that is like an extension used for handling CORS. It helps in enabling CORS in multiple ways like:
The default way to use
flask_cors for all resources in all domains is as follows:
1 2 3 4 5 6 7 8 9 from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route("/") def helloWorld(): return "Hello, cross-origin-world!"
To use a decorator on your own
I will prefer to use this implementation if my use case was to just enable CORS instead of importing a third-party library.
Let’s look into some of the headers used in this method:
Access-Control-Allow-Origin: It indicates whether the response can be shared with requesting code from the given origin.
Access-Control-Allow-Headers: It is used in response to a preflight request which includes the Access-Control-Request-Headers to indicate which HTTP headers can be used during the actual request.
Access-Control-Allow-Methods: It specifies the method or methods allowed when accessing the resource in response to a preflight request.
To use this decorator, just import it and use it over any resources in Flask as following:
@app.route("/predict/tree", methods=["POST", "GET"]) @crossdomain(origin='*') def predict_tree():
Yet both the above approaches are defaulting to set Access-Control-Allow-Origin:
<origin> as per the HTTP standards.
There maybe a ton of other options as well the writer may not know 😅. Just wanted to put that straight out and I am aware flask-restx cors method is just the code script mentioned in method2.
Yet our issue in plain English is to allow just a small list of allowed origins for our API endpoint. For that, we need to check if the requested resource that is to be
shared is part of our list of allowed origins. If yes, set header
Access-control-allow-Origin with that requested resource URL.
Trying to implement with flask-cors library
In configuration docs of flask-cors. It’s defined that Origin can be set as a string, List, regex pattern too. When passed as a string, the entire string of whitelist URLs was being set for the header Access-control-Allow-Origins. So this solution doesn’t work, as expected as our requirement.
TADA finally the solution 🤗
For solving the issue, we had to finally rely
after_request function. It’s a function used to run after each request. It should always
take response as a parameter and should return a new response object or the same one passed. The after_request method doesn’t pass requests
in case of any exceptions in program. Check the link if you are interested to know more about flask after_request and it’s friends.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from flask import request @app.after_request def cors_origin(response): allowed_origins = ['https://kurianbenoy.com', 'https://beautifuljekyll.com/'] if allowed_origins == "*": response.headers['Access-Control-Allow-Origin'] = "*" else: assert request.headers['Host'] if request.headers.get("Origin"): response.headers["Access-Control-Allow-Origin"] = request.headers["Origin"] else: for origin in allowed_origins: if origin.find(request.headers["Host"]) != -1: response.headers["Access-Control-Allow-Origin"] = origin return response
On checking multiple websites, I have noticed sometimes some websites don’t have the header
Referer header always. So we first check if there, such
an Origin exist, if it exists set the
Access-Control-Allow-Origin header as the Origin value, else check if the URL matches the
if yes set that URL in the
If not implemented CORS properly, there is a possibility for using CORS misconfigurations for cracking your website like what was done to a few bitcoin brokers. We all should understand that Same Origin Security Policy is a bedrock of web application security.
Some of the exploitable misconfigurations with CORS are:
- Reflected Origin in Access-Control-Allow-Origin - Most of the real attacks require
Access-Control-Allow-Credentialsto be set True, which is a cause of this vulnerability too. Since developers are setting Access-Control-Allow-Origin dynamical they simply copy the value of Origin header. So this vulnerability can be exposed sometimes when developer checks for domain(victimdomain.com) in Allowed Origin header, then attacker use (attackervictimdomain.com) to steal confediential information.
- Setting as null origin - The specification mentions it being triggered by redirects, and a few stackoverflow posts show that local HTML files also get it. Perhaps due to the association with local files,it’s commonly used by developers and it can be used to sandbox iframe.
More exploitations and misconfigurations with CORS can be found in these links:
Hello dear reader! I have been trying to learn Flask and solve this issue(because I am working on a project with it). I’ve written a few hundred lines of code in Flask over the past 2 years, but honestly, I’m pretty bad at it and don’t know the internal workings yet. So my goal with this approach was to learn enough while not getting confused a lot.
I am sharing my learnings on things which I have struggled inspired by Julia Evans. Please let me know if there is any better approach for this. Thanks for reading 🙏.