Skip to content

IMMEDIATE - Jira blocking GET requests with body payload #1945

Open
@bmcalary-atlassian

Description

@bmcalary-atlassian

Bug summary

Hello Team,
Ben from Atlassian Networking.
We've been rolling out DDOS protection over the last few months.
We've become aware of some API clients sending body payloads in GET requests getting HTTP 403 from our DDOS provider (Cloudfront).
Unfortunately, this is not a rule we can adjust, even with help from AWS. It is a fundamental behavior of Cloudfront.

In our logs we are observing this library occasionally including a 2-byte payload in GET requests, which appears to be a {} string.

We have walked your code and we are not 100% sure where the bug is, but we notice in https://github.com/pycontribs/jira/blob/main/jira/client.py that a {} is occasionally used as a default for data .
And in https://github.com/pycontribs/jira/blob/main/jira/resilientsession.py#L182-L186 these lines

        data = original_kwargs.get("data", None)
        if isinstance(data, dict):
            # mypy ensures we don't do this,
            # but for people subclassing we should preserve old behaviour
            prepared_kwargs["data"] = json.dumps(data)

Do not seem to protect from the data kwarg persisting into the requests session with a {} string.

>>> original_kwargs = {"data": {}}
>>> data = original_kwargs.get("data", None)
>>> isinstance(data, dict)
True
>>> json.dumps(data)
'{}'

It looks like there was an earlier attempt to fix this by @razziel89 in https://github.com/pycontribs/jira/pull/1471/files but this might be incomplete.

We're wondering if the code should be:

        data = original_kwargs.get("data", None)
        if isinstance(data, dict) and data:
            # mypy ensures we don't do this,
            # but for people subclassing we should preserve old behaviour
            prepared_kwargs["data"] = json.dumps(data)

or

        data = original_kwargs.get("data", None)
        if isinstance(data, dict):
            # mypy ensures we don't do this,
            # but for people subclassing we should preserve old behaviour
            if data:
                prepared_kwargs["data"] = json.dumps(data)
            else:
                prepared_kwargs.pop("data", None)

or maybe

        data = original_kwargs.get("data", None)
        if isinstance(data, dict):
            # mypy ensures we don't do this,
            # but for people subclassing we should preserve old behaviour
            if data:
                prepared_kwargs["data"] = json.dumps(data)
            else:
                prepared_kwargs["data"] = None

One thing which gives us pause is we also see some hits on GET /rest/api/2/serverInfo carrying the 2-byte payload, and on code walk cannot see where data might be getting set.

For more information you can see https://developer.atlassian.com/cloud/jira/platform/changelog/#CHANGE-2328 and https://community.atlassian.com/t5/Atlassian-Platform-articles/Jira-Confluence-Cloud-APIs-return-403-Error-The-request-could/ba-p/2928153

Is there an existing issue for this?

  • I have searched the existing issues

Jira Instance type

Jira Cloud (Hosted by Atlassian)

Jira instance version

No response

jira-python version

main

Python Interpreter version

3.9

Which operating systems have you used?

  • Linux
  • macOS
  • Windows

Reproduction steps

-

Stack trace

-

Expected behaviour

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions