Использование PHP/Apache для ограничения доступа к статическим файлам (html, css, img и т.д.)
Допустим, у вас много файлов html, css, js, img и etc в каталоге на вашем сервере. Обычно любой пользователь интернет-земли может получить доступ к этим файлам, просто набрав полный URL-адрес, например: http://example.com/static-files/sub/index.html
Теперь, если вы хотите, чтобы только авторизованные пользователи могли загружать эти файлы? В этом примере, скажем, ваши пользователи сначала регистрируются в URL-адресе: http://example.com/login.php
Как бы вы разрешили зарегистрированному пользователю просматривать файл index.html(или любой из файлов под "статическими файлами" ), но ограничивать файл для всех остальных?
На сегодняшний день у меня появилось два возможных решения:
Решение 1
Создайте следующий файл .htaccess в разделе "static-files":
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)$ ../authorize.php?file=$1 [NC]
И затем в authorize.php...
if (isLoggedInUser()) readfile('static-files/'.$_REQUEST['file']);
else echo 'denied';
Этот файл authorize.php сильно упрощен, но вы получаете идею.
Решение 2
Создайте следующий файл .htaccess в разделе "static-files":
Order Deny,Allow
Deny from all
Allow from 000.000.000.000
И тогда моя страница входа в систему могла бы добавить этот файл .htaccess с IP для каждого пользователя, входящего в систему. Очевидно, для этого также потребуется какая-то процедура очистки, чтобы очистить старые или более не используемые IP-адреса.
Я беспокоюсь, что мое первое решение может стать довольно дорогостоящим на сервере, так как увеличивается количество пользователей и файлов, к которым они обращаются. Я думаю, что мое второе решение будет намного дешевле, но также менее безопасно из-за IP-спуфинга и т.д. Я также опасаюсь, что запись этих IP-адресов в файл htaccess может стать узким местом приложения, если есть много одновременных пользователей.
Какое из этих решений звучит лучше и почему? Или вы можете подумать о совершенно другом решении, которое было бы лучше, чем любое из этих?
Ответы
Ответ 1
Я хотел бы использовать загрузчик PHP для проверки подлинности, а затем вернуть нужные вам файлы. Например, вместо выполнения <img src='picture.jpg' />
Сделайте что-то вроде <img src='load_image.php?image=picture.jpg' />
.
Ваш загрузчик изображений может проверять сеансы, проверять учетные данные и т.д., а затем решать, следует ли возвращать запрошенный файл в браузер. Это позволит вам хранить все ваши защищенные файлы за пределами веб-доступного корня, поэтому никто не собирается просто просматривать их или просматривать там "случайно".
Не забудьте вернуть правильные заголовки в PHP и сделать что-то вроде readfile() в php и вернуть содержимое файла в браузер.
Я использовал эту настройку на нескольких веб-сайтах с большим размером и работает как прелесть.
Изменить: система, которую я сейчас создаю, использует этот метод для загрузки Javascript, изображений и видео, но CSS мы не очень беспокоимся о безопасности.
Ответ 2
X-Sendfile
Там есть модуль для Apache (и других HTTP-серверов), который позволяет вам сообщить HTTP-серверу, чтобы он служил файлу, указанному в заголовке в вашем php-коде:
Итак, ваш php script должен выглядеть так:
// 1) Check access rights code
// 2) If OK, tell Apache to serve the file
header("X-Sendfile: $filename");
2 возможных проблемы:
- Вам нужен доступ для перезаписи правил (.htaccess включен или прямой доступ к файлам конфигурации)
- Вам нужен модуль mod_xsendfile, добавленный в установленный Apache
Вот хороший ответ в другом потоке:
fooobar.com/questions/65289/...
Ответ 3
Я много думал о той же проблеме. Я также недоволен движком PHP, работающим для каждого небольшого ресурса, который обслуживается. Я задал вопрос в том же ключе несколько месяцев назад здесь, но с другим фокусом.
Но у меня просто была очень интересная идея, которая могла бы работать.
-
Поддерживайте каталог с именем /sessions
где-то на вашем веб-сервере.
-
Всякий раз, когда пользователь входит в систему, создайте пустой текстовый файл с идентификатором сеанса в /sessions
. Например. 123456
-
В вашем приложении PHP выполните следующие образы: /sessions/123456/images/test.jpg
-
В вашем файле htaccess есть две команды перенаправления.
-
Тот, который переводит /sessions/123456/images/test.jpg
в /sessions/123456?filename=images/test.jpg
-
Вторая, которая ловит любые вызовы //sessions/(.*)
и проверяет, существует ли указанный файл, используя флаг -f
. Если /sessions/123456
не существует, это означает, что пользователь вышел из системы или истек срок их сеанса. В этом случае Apache отправляет 403 или перенаправляет страницу ошибки - ресурс больше не доступен.
Таким образом, у нас есть квазисеансная аутентификация в mod_rewrite, выполняющая только один "файл существует"!!
У меня нет достаточной рутины для создания операторов mod_rewrite на лету, но они должны быть достаточно легкими для записи. (Я надеюсь с вашей стороны @Gumbo:)
Примечания и оговорки:
-
Истекшие файлы сеансов должны быть быстро удалены с помощью задания cron, если только не возможно проверить файл mtime в .htaccess(что вполне возможно).
-
Изображение/ресурс доступен любому клиенту, пока существует сессия, поэтому нет 100% защиты. Возможно, вы можете обойти это, добавив IP-адрес клиента в уравнение (= имя файла, которое вы создаете), и выполните дополнительную проверку для% {REMOTE_ADDR}. Это продвинутое .htaccess мастерство, но я уверен, что это выполнимо.
-
URL-адреса ресурсов не являются статическими и должны быть загружены каждый раз при входе в систему, поэтому кэширование не выполняется.
Мне очень интересны отзывы об этом, любые недостатки или невозможности, которые я, возможно, упустил, и любые успешные реализации (у меня нет времени на то, чтобы настроить сам тест).
Ответ 4
Создайте переписать карту, которая проверяет учетные данные пользователя и перенаправляет их на соответствующий ресурс или на страницу "отказано в доступе".
Ответ 5
Сохранение содержимого файлов htaccess выглядит кошмаром. Кроме того, ваша заявленная цель заключается в том, чтобы не разрешать пользователям, не прошедшим аутентификацию, не не аутентифицированным клиентским IP-адресам, доступ к этому контенту, поэтому подход не подходит для цели:
Несколько пользователей могут отображаться с одного и того же IP-адреса
Кажется, что сеанс одиночных пользователей поступает из нескольких адресов.
Я беспокоюсь, что мое первое решение может стать довольно дорогостоящим на сервере, так как количество пользователи и файлы, к которым они обращаются, увеличиваются.
Если вы хотите, чтобы ваш контент не выходил, и вы не хотите использовать аутентификацию HTTP, то единственный доступный для доступа к нему доступ к файлам в дополнительном слое логики - единственный разумный выбор. Кроме того, вы не знаете, что с помощью PHP для этой есть проблема - вы ее протестировали? Я думаю, вы будете удивлены, сколько пропускной способности он может обеспечить, особенно если вы используете кеш-код операции.
Я предполагаю ваше "упрощение" проблем с обертками, таких как тип mime и кеширование.
С.
Ответ 6
Я написал динамическое веб-приложение и развернул его на WebShere Application Server, и вот как я защитил свои статические файлы:
Сначала я добавил
<login-config id="LoginConfig_1">
<auth-method>FORM</auth-method>
<realm-name>Form-Based Authentication</realm-name>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login_error.html</form-error-page>
</form-login-config>
</login-config>
в web.xml, который скажет вашему веб-серверу использовать проверку подлинности на основе форм (код для использования логина приведен ниже).
код для страницы входа:
<form id="form1" name="form1" method="post" action="j_security_check" style="padding: 0px 0px 0px 12px;">
Username:
<label>
<input name="j_username" type="text" class="font2" />
</label>
<br />
<br />
Password:
<span class="font2" >
<label>
<input name="j_password" type="password" class="font2" />
</label>
</span>
<br />
<br />
<label>
<input type="submit" class="isc-login-button" name="Login" value="Login" />
</label>
</form></td>
Чтобы сделать регистрацию на основе форм, вы должны настроить свой веб-сервер для использования определенной пользовательской регистрации, которая может быть LDAP или базой данных.
Вы можете объявить свои защищенные ресурсы и всякий раз, когда пользователь пытается получить доступ к такому ресурсу, контейнер автоматически проверяет, прошел ли аутентификация пользователя или нет. Даже вы можете прикреплять роли также к защищенным ресурсам. Для этого я добавил следующий код в свой web.xml
<security-constraint>
<display-name>Authenticated</display-name>
<web-resource-collection>
<web-resource-name>/*</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
<http-method>HEAD</http-method>
<http-method>TRACE</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
<http-method>OPTIONS</http-method>
</web-resource-collection>
<auth-constraint>
<description>Auth Roles</description>
<role-name>role1</role-name>
<role-name>role2</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>role1</role-name>
</security-role>
<security-role>
<role-name>role2</role-name>
</security-role>
Таким образом, этот код не позволит пользователю увидеть какой-либо статический файл (с/*), пока он не войдет в систему под роль role1 и role2. Таким образом, вы можете защитить свои ресурсы.
Ответ 7
Если вы используете apache, вы можете настроить, как показано ниже, в файле .htaccess или httpd.conf. Ниже приведен пример предотвращения доступа к *.inc файлу. Это очень помогает мне.
<Files ~ "\.inc$">
Order allow,deny
Deny from all
</Files>
Подробнее см.: http://www.ducea.com/2006/07/21/apache-tips-tricks-deny-access-to-certain-file-types/.
Ответ 8
Предположим, что вы хотите защитить все свои статические файлы, и вам нужно их от сервера внутри вашего веб-сайта, вы можете защитить все HTTP-методы, кроме HEAD.
Если вы авторизованы, вы делаете запрос заголовка через заголовки и отправляете filecontent как тело.
Конечно, это дорого, но вы защищены и у вас такое же поведение.
Ответ 9
У меня может быть предложение, основанное на iframe
и HTTP_REFERER
, но это не доказательство пули, и это будет зависеть от того, что именно вы хотите защитить с помощью этого доступа.
Но в случае предотвращения полной статической страницы, которая будет отображаться без проверки подлинности, вы можете сделать следующее:
1 - используйте страницу PHP для аутентификации пользователя
2 - перенаправление на другую страницу PHP, содержащую ключ в URL-адресе, и iframe, ссылающийся на ваш статический контент в теле:
<iframe src="static/content.html" />
3 - Тогда в htaccess вы можете проверить ключ внутри HTTP_REFERER следующим образом:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !AUTH_KEY
RewriteCond %{REQUEST_URI} ^/path/to/protected/page$
RewriteRule . - [F]
4 - Наконец, если вы хотите сделать его более динамичным и не использовать один и тот же KEY каждый раз, когда вы можете использовать rewrite map
, как было предложено в ответ от Ignacio Vazquez-Abrams, или создать файл с использованием IP-адреса пользователя в качестве имени файла и проверить, файл существует с помощью REMOTE_ADDR
, а затем удалите файл через некоторое время.
Но имейте в виду, что поведение iframe + HTTP_REFERER может отличаться от одного сеанса браузера к другому, а также REMOTE_ADDR, поэтому его ограничение...