Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Suggestion] Configurable response status code to invalid CORS request #326

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

lavenderses
Copy link

Configurable CORS response code when CORS request is invalid

Thank you for taking look at this PR!

In summary

  • Add CORS option invalid_cors_status_code
    • Configures CORS response code when Access-Control-Allowed-Origin is not in response header
    • For backward compatibility, default value is 200 same as current behaviour.

The default behaviour is SAME as current behaviour.

Details

Background

According to CORS document from WHATWG, CORS protocol can take any response code to CORS request as long as response header contains CORS headers like Access-Control-Allow-Origin.
It does not specify response code and response body.

A successful HTTP response, i.e., one where the server developer intends to share it, to a CORS request can use any status, as long as it includes the headers stated above with values matching up with the request.

A successful HTTP response to a CORS-preflight request is similar, except it is restricted to an ok status, e.g., 200 or 204.

But, there might be some wishes like 'Not to return response to invalid CORS request' for security'. From the WHATWG doc,

Any other kind of HTTP response is not successful and will either end up not being shared or fail the CORS-preflight request. Be aware that any work the server performs might nonetheless leak through side channels, such as timing. If server developers wish to denote this explicitly, the 403 status can be used, coupled with omitting the relevant headers.

So I implemented the feature.

Feature

Add invalid_cors_status_code argument for CORS configuration to flask_cors.CORS and flask_cors.cross_origin.

Note:

  1. Now, Flask-Cors responses to the CORS request with status 200 and response body.
    To maintain the backward compatibility, the argument default value is 200 and does not change response body when invalid_cors_status_code is not passed or passed 200.

  2. Personally, response code to the invalid CORS request should be 403 like Spring Security or 401 if it should be authenticated.
    At least Client Error Response Code in Mozilla HTPP response code doc should be returned, which is from 400 to 499.
    So, by setting variable INVALID_CORS_STATUS_MIN = 400 and INVALID_CORS_STATUS_MAX = 499 in flask_cors/core.py, this feature filters invalid_cors_status_code.
    If other value like 302 is set to invalid_cors_status_code, this sets response status 200(set in INVALID_CORS_DEFAULT_STATUS) and response body ''(set in INVALID_CORS_RESPONSE_DATA).

Checked with nosetests --with-coverage --cover-package=flask_cors.

Thank you so much!

For response code configuration in flask_cors.CORS
and decorator, add the argument.
And, add the argument description how it works.

Signed-off-by: nakanoi <nakanoinryota@gmail.com>
To secure(not to send resources to invalid origin), add
response status code options. Its feature is described
in CORS or cross_origin argument document.

This filters by the condition that ACL_ORIGIN is in
response header or not.
If not, set response status to the value configured
in options, or 200 if the value is not in Clint Error
Reponse Code range(400~499). And, set response body
to empty string for securing resource contnet.

Signed-off-by: nakanoi <nakanoinryota@gmail.com>
Add invalid CORS reseponse code tests for both CORS and
decorator configurations.
Each tests are for 'without options', 'valid options'(which
is the case that invalid_cors_response_code is set to
Client Error Code), and 'invalid options'.

Signed-off-by: nakanoi <nakanoinryota@gmail.com>
@lavenderses
Copy link
Author

@corydolphin
Here are some examples!

Befor change

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask('FlaskCorsAppBasedExample')

CORS(app, origins=['https://valid.com'])

@app.route("/api/v1/users/")
def list_users():
    return jsonify(user="joe")

if __name__ == "__main__":
    app.run()

Valid CORS request

# Returns 'Access-Control-Allow-Origin' header

$ curl -v -H 'Origin: https://valid.com' http://localhost:5000/api/v1/users/
> GET /api/v1/users/ HTTP/1.1
> Host: localhost:5000
> Origin: https://valid.com
> 

< HTTP/1.1 200 OK
< Content-Type: application/json
< Access-Control-Allow-Origin: https://valid.com
< 
{
  "user": "joe"
}

Invalid CORS request

# DOES NOT returns 'Access-Control-Allow-Origin' header

$ curl -v -H 'Origin: https://INVALID.com' http://localhost:5000/api/v1/users/
> GET /api/v1/users/ HTTP/1.1
> Host: localhost:5000
> Origin: https://INVALID.com

< HTTP/1.1 200 OK
< Content-Type: application/json
< 
{
  "user": "joe"
}

After change

from flask import Flask, jsonify

from flask_cors import CORS

app = Flask('FlaskCorsAppBasedExample')

# Add 'invalid_cors_status_code' argumemnt
CORS(app, origins=['https://valid.com'], invalid_cors_status_code=403)

@app.route("/api/v1/users/")
def list_users():
    return jsonify(user="joe")


if __name__ == "__main__":
    app.run()

Valid CORS request

# Returns 'Access-Control-Allow-Origin' header

$ curl -v -H 'Origin: https://valid.com' http://localhost:5000/api/v1/users/
> GET /api/v1/users/ HTTP/1.1
> Host: localhost:5000
> Origin: https://valid.com

< HTTP/1.1 200 OK
< Content-Type: application/json
< Access-Control-Allow-Origin: https://valid.com
{
  "user": "joe"
}

Invalid CORS request

# RETURNS 403(FORBIDDEN) and empty content

curl -v -H 'Origin: https://INVALID.com' http://localhost:5000/api/v1/users/
> GET /api/v1/users/ HTTP/1.1
> Host: localhost:5000
> Origin: https://INVALID.com

< HTTP/1.1 403 FORBIDDEN
< Content-Type: application/json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant