Opened 3 hours ago

Last modified 3 hours ago

#35842 new Bug

JSONField has_key, has_keys, has_any_keys lookups do not properly handle quotes on Oracle and SQLite

Reported by: Simon Charette Owned by:
Component: Database layer (models, ORM) Version: 5.0
Severity: Normal Keywords: oracle sqlite json key quote
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The following test reproduces issues on both Oracle and SQLite

  • tests/model_fields/test_jsonfield.py

    diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py
    index ff42b1a14c..b1090b30ac 100644
    a b def test_has_key_number(self):  
    636636                    [obj],
    637637                )
    638638
     639    def test_has_key_special_chars(self):
     640        value = {
     641            'double"': "",
     642            "single'": "",
     643            "dollar$": "",
     644            "mixed$\"'.": "",
     645        }
     646        obj = NullableJSONModel.objects.create(
     647            value=value
     648        )
     649        obj.refresh_from_db()
     650        self.assertEqual(obj.value, value)
     651        for key in value:
     652            with self.subTest(key=key):
     653                self.assertSequenceEqual(
     654                    NullableJSONModel.objects.filter(value__has_key=key),
     655                    [obj],
     656                )
     657
    639658    @skipUnlessDBFeature("supports_json_field_contains")
    640659    def test_contains(self):
    641660        tests = [

In the case of Oracle the issue arise because it doesn't supporting binding variables in JSON_EXISTS (original discussion) so while the json.dumps of the key is believed to protect from SQL injections it can still result in crashes if the key contains a single quote character. Using the PASSING clause could possibly allow us to bypass this limitation or using a different escaping strategy could possibly be used to adjust the Oracle implementation.

---

In the case of SQLite the problem is with the double-quote character " because escapes generated by json.dumps are not properly interpreted by SQLite.

In other words "foo\"bar" is not properly interpreted as 'foo"bar and while SQLite allows you not to quote keys (e.g. JSON_TYPE(%s, '$.foo\"bar') IS NOT NULL) the solution is not viable for keys that contain both a double-quote and a symbol such as . as exemplified by the mixed key in the provide test.

Change History (2)

comment:1 by Mariusz Felisiak, 3 hours ago

It's related to the #32213.

comment:2 by Natalia Bidart, 3 hours ago

Triage Stage: UnreviewedAccepted
Note: See TracTickets for help on using tickets.
Back to Top