#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.

Reply via email to