Рейтинг:1

Apache: ограничить показ изображений аутентифицированным пользователям

флаг cn
Bob

Я пытаюсь найти способ ограничить доступ к папке мультимедиа в моей конфигурации 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]

Все части сайта, требующие аутентификации, находятся за /приват/ путь, поэтому моя идея заключалась в том, что если это сработает, то переход к /медиа/изображения/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, но я не могу понять, как проверить его на пользовательскую модель Django. Это после этого изменения, я буду получать приглашение войти в систему каждый раз, когда я загружаю страницу, которая отображает изображения (но без htaccess и т. д., нет ничего для аутентификации, и изображения не отображаются на сайте.

Я то попытался реализовать то, что описано здесь (https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/apache-auth/), но моему проекту django не нравится WSGIHandler (в отличие от стандартного get_wsgi_application()). я получаю поднять AppRegistryNotReady("Приложения еще не загружены") ошибка. Кажется, это может быть наиболее разумным подходом, но я не знаю, как получить WSGIHandler работает, или подход, работающий с get_wsgi_application().

Я знаю, что мог бы дать файлам трудно угадываемое имя, похожее на uuid, но это похоже на половинчатое решение. Итак, какова моя наилучшая стратегия для ограничения доступа к папке мультимедиа, чтобы эти изображения были связаны только в той части сайта, где пользователи аутентифицируются?

Убунту 20.04, Апач 2.4

| Редактировать, следуя некоторым советам |

auth.py

def check_password (окружение, имя пользователя, пароль):
    print("---->>>---->>>---->>>---->>>---->>> check_password() была вызвана <<<--- --<<<----<<<----<<<----<<<----")

    вернуть Истина

#из django.contrib.auth.handlers.modwsgi import check_password

Журналы Apache показывают, что этот скрипт загружен, но функция, по-видимому, не выполняется, поскольку оператор печати не появляется в журналах. Я поместил блуждающую инструкцию печати в этот файл и в файл wsgi.py, чтобы убедиться, что эта стратегия попала в журналы, только то, что было в файле wsgi.py, попало в журнал.

vhost:

<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/журнал/apache2/error.log вместо настроенных пользовательских журналов. Не знаю почему, но ладно...

(2) Мой venv не был активирован должным образом, и я на самом деле этого не заметил, потому что django также установлен в системе Python. я скопировал activ_this.py script из virtualenv и добавил его в мой venv и добавил что-то вроде этого в мой файл wsgi

enable_this = '/path/to/ENV/bin/activate_this.py'
с open(activate_this) как f:
    exec(f.read(), {'__file__': активировать_это})

Когда эти вещи исправлены, функция check_password работает при вызове из файла wsgi.py. «работает» здесь означает, что он ограничивает доступ к папке, к которой у неаутентифицированных пользователей не должно быть доступа. Пользователям по-прежнему необходимо вводить учетные данные дважды — один раз в обычном представлении django и один раз в приглашении браузера. Это раздражает, но на самом деле мой вопрос был об ограничении доступа, поэтому я оставлю его на другой день.

Предложение ответа вызвать check_password из auth.py не сотрудничает с моим проектом. Я получаю сообщения об ошибках, которые предполагают, что он вызывается до wsgi.py — кажется, что venv не загружен или настройки не загружены во время вызова check_password.

Рейтинг:1
флаг ve

вот что делает get_wsgi_application:

защита get_wsgi_application():
    django.setup(set_prefix=False) # это приведет к "apps_ready=true"
    вернуть WSGIHandler()

он настраивает среду django перед возвратом обработчика.

Следующее должно помочь в вашем wsgi.py:

приложение = get_wsgi_application()
из django.contrib.auth.handlers.modwsgi импортировать check_password
# важна последовательность!!

На самом деле проблема в первой строке modwsgi.py:

Модель пользователя = auth.get_user_model()

потому что get_user_model() проверит apps_ready и все, что делается в тот момент, когда python выполняет импорт файла!

лучшим способом было бы создать отдельный файл auth.py и сначала проверить, действительно ли он вызывается Apache, с помощью простой печати, которая попадет в журнал ошибок Apache:

def check_password (окружение, имя пользователя, пароль):
    print("*********** check_password() был вызван ********")
    вернуть Истина

После запуска вы можете заменить его оператором импорта и использовать djangos check_password().

из django.contrib.auth.handlers.modwsgi импортировать 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>
флаг cn
Bob
Спасибо! После внесения предложенных вами изменений происходят две странные вещи. 1. Я получаю запрос от браузера на аутентификацию (только в первый раз, но я полагаю, что это должно быть обработано моим входом в систему). 2. Не отображаются изображения из секретной папки — сайт загружается, но запрос img возвращает ошибку 500 («фаза аутентификации «проверка пользователя» дала статус 500» в файлах журнала.) Я не знаю, что это значит & гугл не помогает.
Razenstein avatar
флаг ve
Я меняю ответ выше: создайте отдельный файл "auth.py" (что в любом случае правильно и не смешивайте его со стандартным wsgi.py - я просто хотел, чтобы он был простым в первом ответе) и поместите test функция - тогда вы можете увидеть, вызывает ли Apache вашу функцию «check_password».
Razenstein avatar
флаг ve
если вы хотите отобразить, например. изображение внутри страницы просто использует XSendfile, как вы упомянули в качестве решения (1) - это работает. В функции/представлении, которая обслуживает URL-адрес XSendfile, вы можете ограничить доступ так же, как вы бы ограничили доступ к любому другому представлению. А активировав XSendFile в Apache, любой доступ к соответствующему каталогу будет направлен в ваше приложение django.
флаг cn
Bob
А когда apache не вызывает функцию в auth.py, что тогда? Нужно ли мне как-то импортировать его? Или как-то ссылаться на него в конфигурации apache? Журналы ошибок такие же, как и в первом ответе.
Razenstein avatar
флаг ve
проверьте правильность директивы WSGIAuthUserScript path_to_auth_script/auth.py. Опубликуйте свои httpd-vhost.conf и auth.py.
флаг cn
Bob
разместил в редакции
флаг cn
Bob
На данный момент личная папка скрыта от неавторизованных пользователей, но пользователь должен пройти аутентификацию с помощью приглашения из браузера после того, как уже авторизовался на сайте через обычные представления аутентификации django. Apache не вызывает мой скрипт auth.py, поэтому я предполагаю, что его работа решит проблему дополнительного входа в систему.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.