Apache: 인증된 사용자에게 이미지 제공을 제한합니다.

Apache: 인증된 사용자에게 이미지 제공을 제한합니다.

내 아파치 구성에서 미디어 폴더에 대한 액세스를 제한하는 방법을 찾으려고 합니다. 폴더는 Django 사이트에서 업로드를 가져오고 이미지/PDF 업로드는 인증된 사용자에게 사이트에 표시됩니다. 문제는 인증되지 않은 schmo가 mysite.com/media/images/pic1.jpg. 이것은 불가능합니다. 이 동작을 제한하기 위해 몇 가지 방법을 시도했지만 포인터가 한두 개가 필요한 것 같습니다.

첫 번째 시도 : XSendfile

Xsendfile이 작동하는 것 같았지만 (이름에서 알 수 있듯이) 다운로드할 파일을 보낸 다음 이미지를 표시해야 하는 내 페이지가 로드되지 않습니다. 그래서 이것이 내 사용 사례에 필요한 것이 아닌 것 같습니다.

두 번째 시도: 규칙 다시 작성

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여전히 이미지를 보여줍니다.

세 번째 시도 : 환경

가상호스트 내부 환경에서 비슷한 것을 시도했습니다.

<VirtualHost *:80>
    ...
    SetEnvIf Referer "mysite\.com\/priv" localreferer
    SetEnvIf Referer ^$ localreferer
    <FilesMatch "\.(jpg|png|gif|pdf)$">
        Require env localreferer
    </FilesMatch>
    ...
</VirtualHost>

그러나 이것도 작동하지 않았습니다. 여전히 이미지로 직접 이동할 수 있습니다.

네 번째 시도: 유효한 사용자 필요

v-host에 추가했는데 Require valid-userDjango 사용자 모델과 비교하여 확인하는 방법을 알 수 없습니다. 이 변경 후에는 이미지를 표시하는 페이지를 로드할 때마다 로그인하라는 메시지가 표시됩니다(그러나 htaccess 등이 없으면 인증할 항목이 없으며 사이트에 이미지가 표시되지 않습니다.)

그런 다음 여기에 설명된 내용을 구현하려고 했습니다(https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/apache-auth/WSGIHandler), 하지만 내 django 프로젝트는 (기본값과 반대로 ) 마음에 들지 않습니다 get_wsgi_application(). 오류 가 발생합니다 raise AppRegistryNotReady("Apps aren't loaded yet."). 이것이 가장 합리적인 접근 방식인 것 같지만 WSGIHandler작업을 수행하는 방법이나 get_wsgi_application().

나는 파일에 추측하기 어려운 uuid와 같은 이름을 지정할 수 있다는 것을 알고 있지만 이는 절반 정도의 솔루션인 것 같습니다. 그렇다면 이러한 이미지가 사용자가 인증된 사이트 부분 내에서만 연결되도록 미디어 폴더에 대한 액세스를 제한하는 최선의 전략은 무엇입니까?

우분투 20.04, 아파치 2.4

| 몇 가지 조언에 따라 편집 |

auth.py

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 파일에 잘못된 인쇄 문을 넣었습니다. 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 기능이 아파치 로그에 표시되지 않았습니다. /var/log/apache2/error.log설정된 사용자 정의 로그 대신 에 표시되었습니다 . 왜인지는 모르겠지만, 알았어...

(2) 내 venv가 제대로 활성화되지 않았고 django가 Python 시스템에도 설치되어 있기 때문에 실제로 이것을 눈치 채지 못했습니다. activate_this.pyvirtualenv에서 스크립트를 복사하여 내 venv에 추가하고 이와 같은 sth를 내 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 보기에서, 다른 한 번은 브라우저 프롬프트에서 제공해야 합니다. 짜증나지만 사실 제 질문은 접근 제한에 관한 것이었기 때문에 다음 날로 미루겠습니다.

auth.py에서 check_password를 호출하라는 답변의 제안이 내 프로젝트에 협력하지 않습니다. wsgi.py 이전에 호출되었다는 오류가 표시됩니다. venv가 로드되지 않았거나 check_password가 호출될 때 설정이 로드되지 않은 것 같습니다.

답변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로 이동하는 간단한 인쇄를 통해 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>

관련 정보