Допустим, у вас много файлов 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-адреса.
Какие из этих решений звучат лучше и почему? Или вы можете подумать о совершенно другом решении, которое было бы лучше, чем любое из этих?
Я хотел бы использовать загрузчик PHP для обработки аутентификации, а затем вернуть нужные вам файлы. Например, вместо выполнения <img src='picture.jpg' />
Сделайте что-то вроде <img src='load_image.php?image=picture.jpg' />
.
Ваш загрузчик изображений может проверять сеансы, проверять учетные данные и т. Д., А затем решать, следует ли возвращать запрошенный файл в браузер. Это позволит вам хранить все ваши защищенные файлы за пределами веб-доступного корня, поэтому никто не собирается просто просматривать их или просматривать там «случайно».
Не забудьте вернуть правильные заголовки в PHP и сделать что-то вроде readfile () в php и вернуть содержимое файла в браузер.
Я использовал эту настройку на нескольких крупных веб-сайтах, и это работает как шарм.
Изменить: система, которую я сейчас создаю, использует этот метод для загрузки Javascript, изображений и видео, но CSS мы не очень беспокоимся о защите.
Для Apache (и других HTTP-серверов) есть модуль, который позволяет HTTP-серверу обслуживать файл, указанный вами в заголовке в вашем php-коде: так что ваш php-скрипт должен выглядеть так:
// 1) Check access rights code // 2) If OK, tell Apache to serve the file header("X-Sendfile: $filename");
2 возможных проблемы:
Вот хороший ответ в другом потоке: 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, поэтому его ограничение …