A Riskier JsonResponse
I was reviewing the incredibly insightful collection of Django antipatterns because it was mentioned in Django News #323 and saw something that stuck out.
Return a JsonResponse with safe=False
I sort of remembered that JsonResponse required objects to be returned, but I wasn’t sure why, so I decided to learn more.
It highlights that in 2008, there was a browser exploit that allowed a person to exploit the Array function in JavaScript which allowed them to capture privileged information.
Effectively, returning an array of JSON objects was susceptible to this exploit. When that article was published, only FireFox 2 was vulnerable. Firefox 3 had resolved it, including Chrome and IE 6, 7 and 8.
🤨
Wait…
We’re now on FireFox 147. And IE doesn’t even exist anymore.
Short version: ECMAScript V5 resolved this issue, and we’re good to remove the safe= parameter from JsonResponse (follow along on the Trac ticket).
Removing this parameter reduces the scope of the API, removes code from Django, and eliminates an antipattern from our developer experience.
Why are we safer now?
Presumably, the browsers fixes this back in 2008. It’s hard for me to confirm that though since I couldn’t find a CVE to trace through the fixes.
What I did do is trace the origins of safe= to this commit and this Trac ticket. In it, Łukasz Balcerzak proposes we limit the shape of the JSON being returned:
As for
JSON_RESPONSE_ALLOW_DICTS_ONLY: security flaw would be created if i.e. some view is CSRF vulnerable and returns top-level Array object, and user uses pre-EcmaScript5 compliant browser. Attacker could prepare malicious page with a request to that page. Normally, attacker would not be able to retrieve data from such request but with patched Array it is possible. See http://flask.pocoo.org/docs/security/#json-security to get more information and quite precise example.
I suspect this was partly inspired from Noah Kantrowitz’s work on statusboard because the ticket’s description includes a link to an implementation of JsonResponse which also mentions the Flask security notice.
Which by the way, doesn’t exist anymore either!
That was removed back in 2016 as a part of a JSON security review with a focus on ECMAScript 5. We can find a reference to this JSON security in the current Flask documentation, it’s just moved a bit.
In Flask 0.10 and lower,
jsonify()did not serialize top-level arrays to JSON. This was because of a security vulnerability in ECMAScript 4.ECMAScript 5 closed this vulnerability, so only extremely old browsers are still vulnerable. All of these browsers have other more serious vulnerabilities, so this behavior was changed and
jsonify()now supports serializing arrays.
In summary, the safe= parameter is vestigial and is safe to remove! 🥳
If you have thoughts, comments or questions, please let me know. You can find me on the Fediverse, Django Discord server or via email.