Better permissions for uploaded files in Django
Posted on 2017-08-17 (Updated on 2017-08-17)
Django assigns permissions to any user-submitted files it saves. If you don't explicitly set what these are, it uses an operating system default - which, in most cases, is 0600. If you're unfamiliar with unix-style file permissions, that means the following:
0: The first zero means that this number is an octal, or base 8, number.6: The user that created the file (whatever the Django app is running as, most likely) can read and write to the file0: The group that this file belongs to has no permissions0: Everyone else also has no permissions
That's what I got on my Debian server, and it did not work with the permission scheme I have set up. My backup user is part of the group that these files are assigned to, which means they couldn't be backed up.
Setting octal file permissions
If you want to change the default, you can do so with the FILE_UPLOAD_PERMISSIONS setting in your settings.py.
# Assigns read+write to user, and read only to group
FILE_UPLOAD_PERMISSIONS = 0o640
# Python 2 compatible version
FILE_UPLOAD_PERMISSIONS = 0640
I'm fine with using the old-style octal format, but Python also supplies a better (albeit lightly documented) option.
Using the stat module and bitwise OR
Django's file permissions are governed by python's os.chmod syntax, which itself references the stat module. I'll save you the recursive documentation dive, and show you some of the basics.
The stat module comes with consonants that represent different permissions. Because we're dealing with file uploads, I'll ignore the ones that won't apply.
- User permissions:
S_IRUSRfor read permission,S_IWUSRfor write permission,S_IXUSRfor execute permission, andS_IRWXUfor all three - Group permissions:
S_IRGRPfor read permission,S_IWGRPfor write permission,S_IXGRPfor execute permission, andS_IRWXGfor all three - Other/everyone permissions:
S_IROTHfor read permission,S_IWOTHfor write permission,S_IXOTHfor execute permission, andS_IRWXOfor all three
You combine these constants with a bitwise OR operator, which is a pipe ( | )character, that combines them together as one binary value. That changes my previous example to a much clearer, less cryptic piece of code.
# Assigns read+write to user, and read only to group
import stat
FILE_UPLOAD_PERMISSIONS = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
That makes much more sense for my web server setup.
I would also add that you shouldn't ever add execute permission to files uploaded by users - that would have some very serious security implications!
Tags: python django linux server security