#27590: Prevent public access of staticfiles manifest
------------------------------------------------+------------------------
Reporter: David Sanders | Owner: nobody
Type: Cleanup/optimization | Status: new
Component: contrib.staticfiles | Version: 1.10
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------------+------------------------
A standard Django deploy has all staticfiles accessible to all users. This
is understandable, if undesirable. By itself this is not a huge problem
since those on the public Internet don't know the filenames of all of the
files a deployment has, and fuskering the entire possible namespace isn't
feasible and is also detectable.
However, deployments that make use of `ManifestStaticFilesStorage` will
most likely expose a master list of all static files to anyone who wants
to look. It's not a huge security risk because you shouldn't be depending
on security through obscurity, but there's certainly a leg up given when
there's a master list of all files. Due to the way
`ManifestStaticFilesStorage` is setup, the manifest ends up in the
directory of publicly served files. If the files are stored locally this
can be fixed by blacklisting the file from webserver access and only
letting Django itself read the file off the local filesystem. This is the
approach I've taken once I discovered the issue - I have a server
deployment running Apache serving files on the local filesystem, but have
CloudFront in front of that which fetches from Apache if the cache misses.
I've since blacklisted the staticfiles manifest and invalidated any cached
copies in CloudFront.
Here's what I consider the risks of having a publicly exposed staticfiles
manifest:
- Easily find trade secrets in JavaScript files meant to be used only
internally by staff users
- Find hardcoded secrets in internal files - anything in the static tree
gets listed here, even pre-processed files like coffee or less if the
developers use django-compressor
- Find potential attack vectors by finding normally unlisted files that
are exploitable which could be used to form URLs in phishing emails
- Possible novel way to fingerprint Django versions using the easy master
list of files, could be used to quickly identify potentially vulnerable
Django servers
All that said, I don't have a great solution to the problem that Django
itself could implement. Currently Django writes the manifest to the
staticfiles root so it's always going to be readable unless you take extra
steps. The real stickler is deployments that use something like
[https://github.com/jschneier/django-
storages/blob/master/storages/backends/s3boto.py#L189 S3BotoStorage] which
in effect needs Django to be able to access the manifest remotely. My
understanding of that setup (I don't use it) would be that on load Django
is going to read the manifest from S3, so it needs to be accessible over
the web by default. Further steps could be taken to make it only
accessible to Django itself, but that requires user action.
Potential solutions:
- Encrypt the manifest on disk, decrypt on load into memory - loses human
readability for debugging purposes but hides it from prying eyes by
default
- Fast-track ticket #26029 to make staticfiles storage configuration allow
passing options to storage - use options to change manifest path somewhere
non-public or configure a secret header to use with S3 to only give Django
access to the file.
On a related note, this discovery has made me extra paranoid about the
exposure of internal files meant for staff only and now I'm looking at a
way to formalize restricted access to the files. With the exposure of the
staticfiles manifest it's clear much of the business logic we use (in
JavaScript under admin) is by default visible to the Web if you know the
URL.
--
Ticket URL: <https://code.djangoproject.com/ticket/27590>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/053.df83694679db2913c991c9d10e9f5730%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.