Войти

Показать полную графическую версию : Переход по страницам на PHP


fossil
01-10-2005, 13:36
Привет, недавно начал изучать PHP, и вот пишу сайт.
Имеется главная страница index.php. На ней есть таблица, слева линк $PHP_SELF?action=states, а справа прописано include($inc);

В index.php лежит скрипт типа:
if ($action == "states"){
$inc="states.php";
}

При нажатии все нормально загружается.
На states.php у мен лежит линк такого соджержания $PHP_SELF?action=states&st=01

Вопрос:
Как сделать чтобы при нажатии на этот линк страница открывалась здесь же.
Я пытался сам написать, и вот что вышло:
index.php

if ($action == "states") {
$inc="states.php"
if ($st == $st and $st != "") {
$inc="states/$st.htm";
}
}

Все бы ничего, но если ввести неправильно сформированный запрос, то можно читать любые файлы на сервере :) Вариант с else {$inc="error.htm";} не прокатывает, так как при заходе на states.php вылезает error.htm

Vlad Drakula
01-10-2005, 14:00
fossil
я думаю что настоящая проблемма заключается в том что вы не знаете как это все можно организовать с помощью другово метода?

fossil
01-10-2005, 15:04
Vlad Drakula
Именно так. Ну или возможно как-то переделать этот. Хотя я думал над ним долго....

Vlad Drakula
01-10-2005, 15:48
fossil
если вы опишите свою задачу более подробдо, то я скорее всего смогу предложить вам более простой вариант решения.

fossil
01-10-2005, 16:14
Первая страница (index.php) является как бы шаблоном. Остальные страницы в меню инклюдиться таким образом include("$inc"); Меню имеет вид $PHP_SELF?action=
В зависимости от линка присваиваются параметры :) Тут же эти линки обрабатываются и инклюдится нужная страница. Например

if ($action == "states"){
$inc="states.php";
}

С этим впринципе проблем не возникает.

На странице states.php лежат линки с параметрами $PHP_SELF?action=states&st= в переменную st присваивается номер статьи. Все статьи лежат в каталоге states в htm. Така как у меня states.php инклудится, то все линки на states.php следовательно должны обрабатываться в index.php и инклудиться.

Например у меня в states.php лежит линк $PHP_SELF?action=states&st=01

Следовательно я дописал в index.php следующие строки:

if ($action == "states") {
$inc="states.php"
if ($st == $st and $st != "") {
$inc="states/$st.htm";
}
}

Получается что когда я жму на линк в инклуженном states.php инклудится статья /states/$st.htm (где $st номер статьи).
Вот впринципе и все. Если например сделать запрос http://mysite.ru/index.php?action=states&st=../../../../../../../../../../../../../../etc/passwd%00 нам выведется его содержимое :)

Надо же сделать если ввести что либо другое, то вместо /states/$st.htm инклудилась error.htm, или же как-то сделать подругому запрос.

vadimiron
01-10-2005, 17:53
fossil
Такая система, которую вы создаёте, обычно называется модульной, и states здесь выступает модулем
Есть пару вопросов-предложений:
Во-первых, почему вы пишете
if ($action == "states"){
$inc="states.php";
}

Наверняка у вас будет не только один модуль, а со времен добавяться ещё, тогда может лучше писать так:

if (!empty($action))
{
$inc=$action.".php";
}

Можно также проверять, существует ли вообще такой модуль, если нет, то выводим ошибку "такого модуля нет"

if (!empty($action))
{
if(file_exists($action.".php")) $inc=$action.".php";
else echo "Ошибка: Такой страницы не существует";
}


Обработка переменной $st должна вообще происходить не в index.php, а в том модуле, к которуму она логически принадлежит, то есть в вашем случае в states. Система здесь действует также: проверяем не пуста ли переменная, если нет, то смотрит, существует ли соответствующий данной переменной файл (то есть статья), если существует, то подключаем, если нет, то выводим надпись с ошибкой.

Ещё замечание к модульной системы, если нету переменной action или эта переменная указывает на не существующий модуль, можно подключать стандартный модуль main (или типа того), который будет являться первой страницей сайта

fossil
01-10-2005, 19:37
Спасибо большое!

elfoflorien
01-10-2005, 23:34
fossil
еще не плохо бы проверять переменную $st на наличие ../, ./, /root, /etc, и т. д., иначе, конечно получается очень нехорошая штука:
Если например сделать запрос http://mysite.ru/index.php?action=s..../etc/passwd%00 нам выведется его содержимое

Vlad Drakula
02-10-2005, 10:54
elfoflorien
Если например сделать запрос http://mysite.ru/index.php?action=s..../etc/passwd%00 нам выведется его содержимое
а это значит скорее всего у вас не правильные настройки, раз операционка дала прочитать из пхп этот файл!

elfoflorien
04-10-2005, 14:33
Vlad Drakula
на счет настроек не знаю (где это настраивается в Linux?), но такое у меня получалось и под Linux, и под Windows

vadimiron
04-10-2005, 16:19
elfoflorien
В любом случае достаточно проверять, существует ли такой такой файл, на которой указывает переменная $action. Мы же знаем в какой папке лежат все подобные файлы, вот там и смотрим.

elfoflorien
04-10-2005, 21:59
vadimiron
http://mysite/index.php?action=../../../../../../../etc/passwd
на Unix такой файл существует, поэтому ваша проверка ничего не даст - браузеру будет передан ../../../../../../../etc/passwd, т.е. /etc/passwd
или я чего-то не понял?

vadimiron
04-10-2005, 22:37
elfoflorien
Насчёт такого примера вы правы, но неужели этот файл и вправду вам выдаётся??

В любом случае есть золотое правило: Не доверяем данным, полученным от юзеров-то есть бережённого бог бережёт.
Довольно-таки простой выход, это никогда не передавать имена файлов с расширением, то пишем include($action.html)

fossil
05-10-2005, 13:56
Я сделал так, и вродебы все работает:

if ($action == "states") {
$inc="states.php";
if ($st == $st and !empty($st)) {
if (file_exists("states/$st.php")) {
$inc="states/$st.php";
} else {$inc="error.htm";}
}
} else {$inc="error.htm"}

fossil
05-10-2005, 14:26
Хотя нет, извеняюсь, баг остается прежним :)

fossil
05-10-2005, 14:43
if ($action == "states") {
$inc="states.php";
if ($st == $st and !empty($st)) {
if (file_exists("states/$st.php") and substr($st, 0, 2) != ".." and substr($st, 0, 1) != "/") {
$inc="states/$st.php";
} else {$inc="error.htm";}
}
}

Вот рабочий вариант, правда можно читать все файлы которые в каталоге лежат.

elfoflorien
05-10-2005, 15:43
fossil, vadimiron
как насчет использования метода POST вместо GET? тогда ведь пользователь не сможет так просто подделать имя файла $action; есть, конечно, возможность посмотреть HTML код и послать заголовки и POST, и GET, но все равно пользователь просто так ничего не сделает и не узнает имя переменной, в которой находится путь; потом еще один выход - шифровать содержимое $action, чтобы злоумышленник просто не знал, что туда написать. Можно воспользоваться стандартным алгоритмом PHP, а можно написать свой.

fossil
05-10-2005, 17:42
elfoflorien
Если можешь, пожалуйста про шифрование поподробнее.

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

mar
05-10-2005, 18:04
2All
есть такая замечательная функция basename (http://ru.php.net/manual/en/function.basename.php). Обрезает путь, возвращая собственно имя файла. После чего приставляем свой настоящий путь до файла и плюем на всех кулхцкеров :). (В случаях, когда нет ветвления по каталогам, или его можно легко предопределить, скажем по тому же имени файла, очень даже помагает).
В случае чего можно использовать также dirname (http://ru.php.net/manual/en/function.dirname.php), парсить результат и посылать всех, кто пытается выйти за пределы предопределенного дерева каталогов.

Насчет $_GET и $_POST - elfoflorien абсолютно прав, - только через предопределенные переменные и желательно через $_POST

elfoflorien
fossil
Шифрование - я бы не стала играть в эти игры :), потому, что следующей после этого проблемой встанет проблема индексирования нашего сайта поисковыми системами




© OSzone.net 2001-2012