#37174 closed Bug (fixed)
Template fragment cache key collision for vary_on values containing ":"
| Reported by: | Jacob Walls | Owned by: | Jacob Walls |
|---|---|---|---|
| Component: | Template system | Version: | 6.0 |
| Severity: | Normal | Keywords: | not-security |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The documented example for template fragment caching demonstrates using request.user.username as a vary_on argument. If that username contained :, and another vary_on argument was present, then two cache keys might collide, and the wrong content could be served.
See this PoC provided to the Security Team:
from django.core.cache.utils import make_template_fragment_key a = make_template_fragment_key("frag", ["alice", "b:c"]) b = make_template_fragment_key("frag", ["alice:b", "c"]) assert a == b # same key
We decided against accepting this as a security issue given the unlikelihood of colons in the data most important to vary on from a security perspective, e.g. usernames in a username + language code vary_on pair, but there is a correctness issue to fix here.
One fix strategy would involve incorporating the lengths of the arguments into the cache key.
Since this will cause cache busting, we should probably document in the release note something similar to the note from 5cb3ed187b283059589cb442c56a66a795800cac.
Change History (14)
comment:1 by , 3 weeks ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 3 weeks ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:3 by , 3 weeks ago
| Owner: | changed from to |
|---|
Amar, this one is almost identical to #37101, so if you don't mind, I'm going to fix them both in the same PR to aid review.
comment:4 by , 3 weeks ago
No worries at all, Jacob! You are welcome to take it. A combined PR makes perfect sense here.
comment:6 by , 2 weeks ago
Hi,
I was reviewing this ticket while looking for a small code-related contribution to understand Django’s contribution workflow. I noticed that the ticket is already assigned, so I won’t work on it directly.
I tried to reproduce the issue locally using the example from the ticket description:
make_template_fragment_key("frag", ["alice", "b:c"])
and
make_template_fragment_key("frag", ["alice:b", "c"])
Both calls generated the same cache key:
template.cache.frag.486f15e693cb74d155ff00eb53e7e306
I also added a small local regression test in tests/cache/tests.py, inside TestMakeTemplateFragmentKey, to check that these two keys should be different. As expected, the test fails on the current branch, so the reported behavior is reproduced.
I hope this helps with testing or triage. I’d be happy to test a proposed patch if needed.
comment:7 by , 2 weeks ago
Hi there. The attached PR is almost mergable, awaiting re-review on the release note. Any comments welcome!
comment:8 by , 13 days ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Thanks!