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

FlaskIntegration JSON BadRequest with Werkzeug >= 2.1.0 #1936

Closed
cc-jj opened this issue Mar 2, 2023 · 5 comments
Closed

FlaskIntegration JSON BadRequest with Werkzeug >= 2.1.0 #1936

cc-jj opened this issue Mar 2, 2023 · 5 comments
Assignees
Labels
Type: Bug Something isn't working

Comments

@cc-jj
Copy link

cc-jj commented Mar 2, 2023

How do you use Sentry?

Sentry Saas (sentry.io)

Version

1.16.0

Steps to Reproduce

  1. Create a Flask application. Werkzeug must be >= 2.1.0.

Werkzeug 2.1.0 changed the default behavior of Request.get_json(). See here:

Request.get_json() will raise a 400 BadRequest error if the Content-Type header is not application/json. This makes a very common source of confusion more visible. [#2339](https://github.com/pallets/werkzeug/issues/2339)
> python3 -m pip install --upgrade 'sentry-sdk[flask]'
> python3 -m pip freeze
blinker==1.5
certifi==2022.12.7
click==8.1.3
Flask==2.2.3
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.2
sentry-sdk==1.16.0
urllib3==1.26.14
Werkzeug==2.2.3

Application code:

import sentry_sdk
from flask import Flask
from sentry_sdk.integrations.flask import FlaskIntegration


sentry_sdk.init(
    integrations=[FlaskIntegration()],
    traces_sample_rate=1.0,
    debug=True,
)

app = Flask("app")


@app.route("/", methods=["GET"])
def index():
    return "ok", 200


if __name__ == "__main__":
    app.run("localhost", port=5000)
  1. Run the flask server
> python3 app.py
  1. Send a request
> curl http://localhost:5000/

Expected Result

There should not be any internal error in sentry_sdk.

Actual Result

There was an internal error in sentry_sdk. From the application logs:

[sentry] DEBUG: [Tracing] Starting <http.server> transaction <generic WSGI request>
 [sentry] DEBUG: [Profiling] Discarding profile because profiler was not started.
 [sentry] ERROR: Internal error in sentry_sdk
Traceback (most recent call last):
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/flask/wrappers.py", line 128, in on_json_loading_failed
    return super().on_json_loading_failed(e)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/werkzeug/wrappers/request.py", line 631, in on_json_loading_failed
    raise BadRequest(
werkzeug.exceptions.BadRequest: 400 Bad Request: Did not attempt to load JSON data because the request Content-Type was not 'application/json'.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/sentry_sdk/integrations/flask.py", line 196, in inner
    FlaskRequestExtractor(request).extract_into_event(event)
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/sentry_sdk/integrations/_wsgi_common.py", line 69, in extract_into_event
    parsed_body = self.parsed_body()
                  ^^^^^^^^^^^^^^^^^^
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/sentry_sdk/integrations/_wsgi_common.py", line 112, in parsed_body
    return self.json()
           ^^^^^^^^^^^
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/sentry_sdk/integrations/flask.py", line 176, in json
    return self.request.get_json()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/werkzeug/wrappers/request.py", line 591, in get_json
    return self.on_json_loading_failed(None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../third-party/sentry-bug/env/lib/python3.11/site-packages/flask/wrappers.py", line 133, in on_json_loading_failed
    raise BadRequest() from e
werkzeug.exceptions.BadRequest: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.

Proposed solution

Use request.get_json(silent=True) which works with Werkzeug before and after 2.1.0.

@cc-jj
Copy link
Author

cc-jj commented Mar 3, 2023

Snyk has identified Werkzeug < 2.2.3 as a security vulernability. Hence this is causing a headache for me (and I'm sure others).

In the meantime I've upgraded Werkzeug to 2.2.3 and monkeypatched sentry's FlaskRequestResolver.get_json method.

The patch is quite simple:

def get_json(self):
    return self.request.get_json(silent=True)

@antonpirker antonpirker added Status: Backlog Type: Bug Something isn't working and removed Status: Untriaged labels Mar 3, 2023
@antonpirker antonpirker self-assigned this Mar 3, 2023
@antonpirker
Copy link
Member

Hey @cc-jj
We merged a fix for Werkzeug > 2.1 in our Flask integration (see #1939 )
This will probably be released in 1-2 weeks.

@antonpirker
Copy link
Member

Another thing @cc-jj : can you check if the current master branch of the SDK fixes this problem?

@cc-jj
Copy link
Author

cc-jj commented Mar 3, 2023

@antonpirker I confirm the bug has been fixed on master. Thanks.

@antonpirker
Copy link
Member

Great! So I am closing this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants