#21098 closed Bug (fixed)
MultiValueDictKeyError leaks sensitive POST data
Reported by: | Simon Percivall | Owned by: | Tim Graham |
---|---|---|---|
Component: | Core (Other) | Version: | dev |
Severity: | Release blocker | Keywords: | |
Cc: | Jonas Borgström | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Getting an error in MultiValueDict
on a POST, such as doing request.POST['foo']
, will leak the POST data without any escaping by Django, i.e. the MultiValueDictKeyError
contains an unescaped repr
of request.POST
, no matter if you've added for instance @sensitive_post_parameters("password")
.
Change History (11)
comment:1 by , 11 years ago
Description: | modified (diff) |
---|
comment:2 by , 11 years ago
Component: | Uncategorized → Core (Other) |
---|---|
Owner: | changed from | to
Severity: | Normal → Release blocker |
Status: | new → assigned |
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Bug |
Version: | 1.5 → master |
comment:3 by , 11 years ago
Has patch: | set |
---|---|
Patch needs improvement: | set |
comment:4 by , 11 years ago
Cc: | added |
---|
comment:5 by , 11 years ago
Resolution: | → wontfix |
---|---|
Status: | assigned → closed |
If I understand correctly, this ticket is about Django's debug page, which is only displayed when DEBUG = True
.
sensitive_post_parameters
is only supported when DEBUG = False
.
Relevant excerpt from the error reporting docs:
Django offers a set of function decorators to help you control which information should be filtered out of error reports in a production environment (that is, where
DEBUG
is set toFalse
)
I'm going to close this ticket for this reason, and for a few others I describe below.
Tim's first attemps shows that it will be very hard to scrub sensitive variables. They may end up anywhere in the stack trace. For instance, if a function contains hash_src = (salt + password).encode('utf-8')
, and Django displays the value of local variables in that frame, the value of the password will appear on screen. It seems impossible to defend against all leaking scenarios in the context of a debug page that aims at displaying as much information as possible.
Even if it we had a strong mechanism to mask sensitive variables in the debug page (like looking at their value and replacing it with a placeholder in the generated HTML), I'm not sure it would be a good idea. It's very frustrating when a debugging tool hides the information you need. In a debug page used only in development (when DEBUG = True
), it makes sense to priorize debugging capabilities. While it's annoying to read one's password on screen, the cure may be worse than the disease.
Leaking POST data in the debug page isn't much of an issue. The data was entered by a developer working on the project, and it's leaked to the same developer.
sensitive_post_parameters
is designed to avoid leaking data in logs or error reports, not in generated HTML, and especially not in the debug page.
comment:6 by , 11 years ago
I don't believe the concern here is the debug page, repr of the request, including post data, is sent by default email handler (not HTML version).
comment:7 by , 11 years ago
Resolution: | wontfix |
---|---|
Status: | closed → new |
Yes, correct; this information is included by the AdminEmailHandler, and by any other loggers, and that is why it's a real issue.
comment:8 by , 11 years ago
#15625 (removing the dictionary from the MultiValueDictKeyError
message) will fix this for plain text emails sent by AdminEmailHandler
.
HTML email is another matter because local variables are included which includes the self
variable in MultiValueDict.__getitem__
which is the unsanitized POST dict. We may be better off adding some warnings to the documentation than trying to make this protection bulletproof as it seems exceedingly difficult to do so.
comment:9 by , 11 years ago
Patch needs improvement: | unset |
---|
comment:10 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
This seems like a tricky one. I took a stab at some initial ideas, but it's still possible to leak data with this approach.
https://github.com/django/django/pull/1624