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_IRUSR
for read permission,S_IWUSR
for write permission,S_IXUSR
for execute permission, andS_IRWXU
for all three - Group permissions:
S_IRGRP
for read permission,S_IWGRP
for write permission,S_IXGRP
for execute permission, andS_IRWXG
for all three - Other/everyone permissions:
S_IROTH
for read permission,S_IWOTH
for write permission,S_IXOTH
for execute permission, andS_IRWXO
for 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