Djangoアプリに複数のFileFieldがあり、異なるユーザーに属することができます。ファイルの所有者ではないユーザーのファイルへのアクセスを制限するための良い方法を探しています。
これを達成するための最良の方法は何ですか?何か案は?
残念ながら、@ Mikkoのソリューションは、Djangoがファイルを提供するように設計されていないため、実際には本番環境では機能しません。本番環境ではファイルを提供する必要がありますHTTPサーバー(Apache、nginxなど)およびnotアプリケーション/ Djangoサーバー(uwsgi、gunicorn、mod_wsgiなど)によって。
そのため、ファイルアクセスの制限は非常に簡単ではありません:HTTPサーバーが、ファイルを要求している特定のユーザーにファイルを提供してもよいかどうかをアプリケーションサーバーに尋ねる方法が必要です。ご理解いただけると思いますが、これにはアプリケーションとhttpサーバーの両方を変更する必要があります。
上記の問題に対する最善の解決策は、X-SendFileメカニズムを使用して上記を実装するDjango-sendfile( https://github.com/johnsensible/Django-sendfile )です。プロジェクトの説明からコピーしています:
これは、Webクライアントにファイルを送信するためのWebサーバー固有のメソッドのラッパーです。これは、Djangoがファイルに関連付けられたアクセス許可を確認する必要があるが、ファイル自体の実際のバイトを提供したくない場合に役立ちます。つまり、大きなファイルを提供することはDjangoのために作られています。
Senfileメカニズムの詳細については、次の回答をお読みください: Django-X-Sendfileを理解する
2018 Update:Django-sendfileはもう維持されていないようです。おそらくまだ機能しているはずですが、同様の機能を備えたより最新のパッケージが必要な場合は、コメント投稿者@ surfer190が提案するように https://github.com/edoburu/Django-private-storage を参照してください。特に、「大きなファイル転送の最適化」セクションを実装していることを確認してください。実際には、大きなファイルだけでなく、すべての転送にこれが必要です。
これは、サーバーによって最も適切に処理されます。 nginx セキュアリンクモジュール (nginxは--with-http_secure_link_module
でコンパイルする必要があります)
ドキュメントからの例:
location /some-url/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr some-secret";
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
if ($secure_link = "1") {
// authorised...
}
}
ファイルには次のようにアクセスします。
/some-url/some-file?md5=_e4Nc3iduzkWRm01TBBNYw&expires=2147483647
(これは時間制限があり、そのIPアドレスのユーザーにバインドされます)。
ユーザーに渡すトークンを生成するには、次のようなものを使用します。
echo -n 'timestamp/some-url/some-file127.0.0.1 some-secret' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
適度なセキュリティが必要な場合、私のアプローチは次のようになります。
1)ユーザーがファイルをアップロードするときに、推測しにくいパスを生成します。たとえば、/ staticフォルダーにアップロードされたファイルごとにランダムに生成された名前のフォルダーを作成できます。このサンプルコードを使用すると、これを非常に簡単に行うことができます。
_file_path = "/static/" + os.urandom(32).encode('hex') + "/" + file_name
_
このように、他のユーザーのファイルがどこに保存されているかを推測するのは非常に困難です。
2)データベースで、所有者をファイルにリンクします。スキーマの例は次のとおりです。
uploads(id, user_id, file_path)
3)次のように、モデル内のFileFieldsのプロパティを使用して、ファイルへのアクセスを制限します。
_class YourModel(models.Model)
_secret_file = models.FileField()
def get_secret_file(self):
# check in db if the user owns the file
if True:
return self._secret_file
Elif:
return None # or something meaningful depanding on your app
secret_file = property(get_secret_file)
_
通常、プライベートファイルは、Apache、Nginx、または使用しているWebサーバーを介して直接提供される通常の静的ファイルを介してルーティングされません。代わりに、パーミッションチェックを処理してファイルをストリーミングダウンロードとして返すカスタムDjangoビューを作成します。
ファイルが特別なプライベートフォルダーフォルダーにあり、Djangoの_MEDIA_URL
_または_STATIC_URL
_を介して公開されていないことを確認してください
するビューを書く
ユーザーがビューロジック内のファイルにアクセスできることを確認します
Pythonのopen()
でファイルを開きます
ファイルのハンドルをパラメータhttp.HttpResponse(_file, content_type="text/plain")
として取得するHTTP応答を返します
たとえば、download()
here を参照してください。