
Apache 設定でメディア フォルダへのアクセスを制限する方法を見つけようとしています。このフォルダは Django サイトからのアップロードを受け取り、画像/PDF のアップロードは認証されたユーザーのサイトに表示されます。問題は、認証されていない誰でも に移動できることですmysite.com/media/images/pic1.jpg
。これはあり得ないはずです。この動作を制限するためにいくつかのことを試しましたが、1 つまたは 2 つのヒントが必要だと思います。
最初の試み: XSendfile
Xsendfile は動作しているように見えましたが、(名前が示すように) ファイルをダウンロード用に送信するため、画像を表示するはずのページが読み込まれません。したがって、これは私のユースケースに必要なものではないようです。
2回目の試行: ルールの書き換え
Apache 設定にいくつかの書き換えルールを追加しました:
RewriteCond "%{HTTP_REFERER}" "!^$"
RewriteCond "%{HTTP_REFERER}" "!mysite.com/priv/" [NC]
RewriteRule "\.(gif|jpg|png|pdf)$" "-" [F,NC]
認証を必要とするサイトのすべての部分は/priv/
パスの背後にあるため、これが機能する場合は、ナビゲートが書き換えられると考えました/media/images/pic1.jpg
。しかし、これも機能せず、mysite.com/media/images/pic1.jpg
画像が表示されたままです。
3回目の試み:環境
仮想ホスト内の環境で同様のことを試してみました:
<VirtualHost *:80>
...
SetEnvIf Referer "mysite\.com\/priv" localreferer
SetEnvIf Referer ^$ localreferer
<FilesMatch "\.(jpg|png|gif|pdf)$">
Require env localreferer
</FilesMatch>
...
</VirtualHost>
しかし、これも機能しませんでした。画像に直接移動することはできます。
4回目の試行: 有効なユーザーが必要
v-host に追加しましたRequire valid-user
が、Django ユーザー モデルに対して確認する方法がわかりません。この変更後、画像を表示するページを読み込むたびにログインを求めるプロンプトが表示されます (ただし、htaccess などがない場合、認証するものはなく、サイトには画像が表示されません)。
そこで、ここで説明されていることを実装してみました(apache-auth は、以下の URL からダウンロードできます。WSGIHandler
) ですが、私の Django プロジェクトでは(デフォルトの とは対照的に)が使用できませんget_wsgi_application()
。エラーが発生します。これが最も合理的なアプローチのように思えますが、を機能させる方法や、 で を機能させる方法がraise AppRegistryNotReady("Apps aren't loaded yet.")
わかりません。WSGIHandler
get_wsgi_application()
ファイルに推測しにくい uuid のような名前を付けることもできることはわかっていますが、これは中途半端な解決策のように思えます。では、これらの画像がユーザーが認証されているサイトの部分内でのみリンクされるように、メディア フォルダーへのアクセスを制限するための最善の戦略は何でしょうか。
Ubuntu 20.04、Apache 2.4
| いくつかのアドバイスに従って編集します |
認証
def check_password(environ, username, password):
print("---->>>---->>>---->>>---->>>---->>> check_password() has been called <<<----<<<----<<<----<<<----<<<----")
return True
#from django.contrib.auth.handlers.modwsgi import check_password
Apache ログには、このスクリプトがロードされたことが示されていますが、print ステートメントがログに表示されないため、関数は実行されていないようです。この戦略がログに記録されるように、このファイルと wsgi.py ファイルに余分な print ステートメントを配置しましたが、wsgi.py ファイルにあったものだけがログに記録されました。
仮想ホスト:
<VirtualHost *:80>
ServerName mysite.com
ServerAlias mysite.com
DocumentRoot /path/to/docroot/
Alias /static/ /path/to/docroot/static/
# Not sure if I need this
Alias /media/ /path/to/docroot/media/
<Directory /path/to/docroot/static/>
Require all granted
</Directory>
<Directory /path/to/docroot/media/>
Require all granted
</Directory>
# this is my restricted access directory
<Directory /path/to/docroot/media/priv/>
AuthType Basic
AuthName "Top Secret"
AuthBasicProvider wsgi
WSGIAuthUserScript /path/to/docroot/mysite/auth.py
Require valid-user
</Directory>
<Directory /path/to/docroot/mysite/>
<Files "wsgi.py">
Require all granted
</Files>
</Directory>
WSGIDaemonProcess open-ancestry-web python-home=/path/to/ENV/ python-path=/path/to/docroot/ processes=10 threads=10
WSGIProcessGroup mysite-pgroup
WSGIScriptAlias / /path/to/docroot/mysite/wsgi.py
LogLevel trace8
ErrorLog "|/bin/rotatelogs -l /path/to/logs/%Y%m%d-%H%M%S_443errors.log 30"
CustomLog "|/bin/rotatelogs -l /path/to/logs/%Y%m%d-%H%M%S_443access.log 30" combined
</VirtualHost>
|別の編集|
すべてが機能するようになったので、回答を受け入れました。多くの可動部分があり、それが回答の最初の問題を引き起こしました。(1) テストの check_password 関数が Apache ログに表示されませんでした.../var/log/apache2/error.log
セットアップされたカスタム ログの代わりに表示されていました。理由はわかりませんが、わかりました...
(2) 私のvenvは適切にアクティブ化されていませんでしたが、djangoがシステムPythonにもインストールされているため、実際にはこれに気づきませんでした。私はactivate_this.py
スクリプトをvirtualenvからコピーしてvenvに追加し、wsgiファイルに次のようなものを追加しました。
activate_this = '/path/to/ENV/bin/activate_this.py'
with open(activate_this) as f:
exec(f.read(), {'__file__': activate_this})
これらの問題を修正すると、wsgi.py ファイルから呼び出されたときに check_password 関数が機能します。ここでの「機能する」とは、認証されていないユーザーがアクセスできないフォルダーへのアクセスを制限することを意味します。ユーザーは、通常の Django ビューで 1 回、ブラウザー プロンプトで 1 回、合計 2 回、資格情報を提供する必要があります。これはイライラしますが、実際、私の質問はアクセス制限に関するものだったので、別の日に残しておきます。
auth.py から check_password を呼び出すという回答の提案は、私のプロジェクトでは機能しません。wsgi.py の前に呼び出されることを示唆するエラーが表示されます。check_password が呼び出された時点で venv が読み込まれていないか、設定が読み込まれていないようです。
答え1
get_wsgi_application が実行しているのは次のことです:
def get_wsgi_application():
django.setup(set_prefix=False) # this will lead to "apps_ready=true"
return WSGIHandler()
ハンドラを返す前に Django 環境をセットアップしています。
wsgi.py で次のようにすればうまくいくはずです:
application = get_wsgi_application()
from django.contrib.auth.handlers.modwsgi import check_password
# the sequence is important!!
実際、問題は modwsgi.py の最初の行にあります。
UserModel = auth.get_user_model()
get_user_model() は apps_ready をチェックし、Python がファイルのインポートを実行した瞬間にすべてが完了するからです。
より良い方法は、別の auth.py を作成し、最初に Apache の error.log に出力される単純な print を使用して、それが実際に Apache によって呼び出されているかどうかを確認することです。
def check_password(environ, username, password):
print("*********** check_password() has been called ********")
return True
これが実行されたら、import ステートメントに置き換えて、djangos check_password() を使用できます。
from django.contrib.auth.handlers.modwsgi import check_password
次に、httpd-vhosts.conf に次の内容を追加します。
<VirtualHost *:80>
....
<Directory path_to_server_root/secret>
AuthType Basic
AuthName "Top Secret"
AuthBasicProvider wsgi
WSGIAuthUserScript path_to_wsgi/wsgi.py
Require valid-user
</Directory>
</VirtualHost>