Использование 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 (или любой из файлов под «static-files»), но ограничивать файл для всех остальных?

До сих пор я придумал два возможных решения:

Решение 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 может стать узким местом приложения, если есть много одновременных пользователей.

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

Я хотел бы использовать загрузчик PHP для обработки аутентификации, а затем вернуть нужные вам файлы. Например, вместо выполнения <img src='picture.jpg' /> Сделайте что-то вроде <img src='load_image.php?image=picture.jpg' /> .

Ваш загрузчик изображений может проверять сеансы, проверять учетные данные и т. Д., А затем решать, следует ли возвращать запрошенный файл в браузер. Это позволит вам хранить все ваши защищенные файлы за пределами веб-доступного корня, поэтому никто не собирается просто просматривать их или просматривать там «случайно».

Не забудьте вернуть правильные заголовки в PHP и сделать что-то вроде readfile () в php и вернуть содержимое файла в браузер.

Я использовал эту настройку на нескольких крупных веб-сайтах, и это работает как шарм.

Изменить: система, которую я сейчас создаю, использует этот метод для загрузки Javascript, изображений и видео, но CSS мы не очень беспокоимся о защите.

X-Sendfile

Для Apache (и других HTTP-серверов) есть модуль, который позволяет HTTP-серверу обслуживать файл, указанный вами в заголовке в вашем php-коде: так что ваш php-скрипт должен выглядеть так:

 // 1) Check access rights code // 2) If OK, tell Apache to serve the file header("X-Sendfile: $filename"); 

2 возможных проблемы:

  1. Вам необходимо получить доступ к правилам перезаписи (включен .htaccess или прямой доступ к файлам конфигурации)
  2. Вам нужен модуль mod_xsendfile, добавленный в установленный Apache

Вот хороший ответ в другом потоке: https://stackoverflow.com/a/3731639/2088061

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

Но у меня просто была очень интересная идея, которая могла бы работать.

  • Ведение каталога /sessions где-то на вашем веб-сервере.

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

Мне очень интересны отзывы об этом, любые недостатки или невозможности, которые я, возможно, упустил, и любые успешные реализации (у меня нет времени прямо сейчас, чтобы настроить тест).

Создайте карту перезаписи, которая проверяет учетные данные пользователя и перенаправляет их на соответствующий ресурс или на страницу «отказано в доступе».

Сохранение содержимого файлов htaccess выглядит кошмаром. Кроме того, ваша заявленная цель заключается в том, чтобы не разрешать пользователям, не прошедшим аутентификацию, не не аутентифицированные клиентские IP-адреса, доступ к этому контенту – поэтому подход не подходит для цели:

Несколько пользователей могут отображаться с одного и того же IP-адреса

Кажется, что один сеанс пользователя поступает из нескольких адресов.

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

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

Я угадываю ваше «упрощение» проблем с обертками, таких как тип mime и кеширование.

C.

Я написал динамическое веб-приложение и развернул его на 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. Таким образом, вы можете защитить свои ресурсы.

Если вы используете 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/ .

Предположим, что вы хотите защитить все свои статические файлы, и вы должны их обслуживать внутри вашего веб-сайта , вы можете защитить все HTTP-методы, кроме HEAD. Если вы авторизованы, вы делаете запрос заголовка через заголовки и отправляете filecontent как тело. Конечно, это дорого, но вы защищены, и у вас одинаковое поведение.

У меня может быть предложение, основанное на 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, поэтому его ограничение …