Template fragment caching potentially harmful
See original GitHub issueIssue Summary
Django provides optional template fragment caching wherein a portion of a template is cached when it is first rendered and that cache is reused to render that portion of the page until the cache expires or is invalidated.
Wagtail provides two ways of viewing pages that have unpublished content: “Preview” and “View Draft.”
Used in conjunction, these features can create scenarios in which live data may be cached and then rendered in preview OR in which draft data may be cached and rendered on the live site. The former is annoying, the latter is a potential vulnerability that could inadvertently leak unpublished information 😱
Since this behavior exists because all the parts are behaving as designed, it’s not 100% clear to me what the solution should be. I can imagine a few possible solutions off the top of my head:
- Add a note to the documentation somewhere cautioning against the use of template fragment caching for this reason
- Somehow add Wagtail-specific behavior to the Django
{% cache %}
tag that causes it to no-op in draft and preview modes (may be possible through middleware or the cache API? not sure) - Create a Wagtail-specific template fragment caching system that respects draft and preview modes
Steps to Reproduce
Start with a Wagtail project with the following files:
models.py
from django.db import models
from wagtail.core.models import Page
from wagtail.admin.edit_handlers import FieldPanel
class HomePage(Page):
a_charfield = models.CharField(max_length=255)
content_panels = Page.content_panels + [
FieldPanel('a_charfield')
]
templates/home/home_page.html
{% load cache %}
{% cache 3600 homepage_charfield %}
{{ self.a_charfield }}
{% endcache %}
(Generate and run all migrations, create necessary admin user, etc.)
From the Wagtail admin, edit and publish a new Home Page:
DO NOT visit this page. Edit the page again with new values:
Do not save, but click “Preview.” You’ll see a previewed page that says “Privileged Information.” Now, load up the live page. Observe that it also renders “Privileged Information” even though that is unsaved content that an editor was merely testing.
- I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: Yes
Technical details
Tested on:
- Python version: Python 3.7.2
- Django version: Django 2.1.7
- Wagtail version: Wagtail 2.4
Issue Analytics
- State:
- Created 5 years ago
- Reactions:2
- Comments:6 (4 by maintainers)
For anyone who wants to implement a workaround until a solution is found in core, I’ve done this:
This (a) doesn’t deal with caching outside of templates and (b) will not work for template fragments that don’t have
request
in the context - so it only partially mitigates the security risk posed by this bug.Similarly to @solarissmoke 's solution, this is the modified version of the jinja2 cache tag from django-jinja .