投稿日:2020年11月2日
Django2では大容量のファイルのアップロードをすると、権限が600になってしまう場合があります。この記事ではその問題の原因と解決方法について解説しています。
DjangoのImageFieldでユーザーにファイルをアップロードしてもらう機能を作った際に、
容量の小さなファイルでは-rw-r--r--でファイルが保存されるのに、サイズが大きくなると-rw-------で保存されてしまうしまうという問題がおきました。
nginxではこのような権限のファイルは403Forbiddenになってしまいます!!
DjangoのFileField(ImageFieldはこれを継承)はアップロードされたデータをUpload Handlerにわたします。どのUpload Handlerを使うのかはsettings.pyの FILE_UPLOAD_HANDLERSで設定するのですが、
この値のデフォルト値は
FILE_UPLOAD_HANDLERS = ["django.core.files.uploadhandler.MemoryFileUploadHandler",
"django.core.files.uploadhandler.TemporaryFileUploadHandler"]
になっています。
この場合、小さいファイルはMemoryFileUploadHandlerで扱い、大きいサイズのファイルはTemporaryFileUploadHandlerで扱うようになります。
TemporaryFileUploadHandlerはsettings.pyのFILE_UPLOAD_PERMISSIONSで指定したパーミッションでファイルの作成を行います。
Django2ではこのFILE_UPLOAD_PERMISSIONSのデフォルト値は
FILE_UPLOAD_PERMISSIONS = None
になっています。
この時、パーミッションはOSに依存するのですが、多くのOSではこの値は600(つまり-rw-------)になっています。
つまりこれが原因で大きいサイズのファイルだけパーミッションが変わってしまったのですね!!
解決策は簡単です。
TemporaryFileUploadHandlerのパーミッションを適切な値(今回は644ですね)に設定してあげればいいです。
FILE_UPLOAD_PERMISSIONSの値は8進数で設定します。
よって
[...]
FILE_UPLOAD_PERMISSIONS = 0o644
[...]
と設定してあげればOKです。
もともと他者に公開する目的のファイルなら問題ないのですが、
大きいサイズのファイルとして考えられるのは例えば履歴書やポートフォリオなどの他者に公開しない事を前提としたファイルが多いはずです。
その様なファイルを、たとえWebサーバーで公開していないディレクトリであるとはいえ、他者が読み取れる権限にしておくのは非常に危険なことです。
その点だけ覚えておくと良いでしょう。