За последние 24 часа нас посетили 36915 программистов и 7184 робота. Сейчас ищут 1606 программистов ...

Работа с "REQUEST_URI" и безопасность

Тема в разделе "PHP для новичков", создана пользователем Булат Азат улы, 9 апр 2023.

  1. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    Всех приветствую, товарищи!
    У меня на сайте обычные страницы гененрируются на index.php с помощью
    PHP:
    1. switch($_SERVER["REQUEST_URI"]){
    2. case "/":
    3.  
    4. break;
    5. }
    А для зоны администратора создал отдельный файл administrator.php, в который попадаешь, если есть сессия (вводя логин и пароль).
    Опытным программистам есть два вопроса, не могли бы помочь:
    1 вопрос - можно ли и в файле administrator.php сделать генерацию по
    PHP:
    1. switch($_SERVER["REQUEST_URI"]){
    2. case "/administrator/":
    3.  
    4. break;
    5. case "/administrator/remont/":
    6.  
    7. break;
    8. }
    , или как-то подобным образом?

    2 вопрос - ниже приведу мой код на index.php и administrator.php - не могли бы подсказать, безопасно ли так (имею ввиду вход в админ. зону) или нужно что-то изменить?
    index.php:
    PHP:
    1. <?php
    2. require_once("config.php");
    3.  
    4. switch($_SERVER["REQUEST_URI"]){
    5. case "/":
    6.     $title = "";
    7.     $description = "";
    8.     $keywords = "";
    9.     $content = "";
    10. break;
    11.  
    12. case "/administrator/":
    13.     session_start();
    14.     if (isset($_SESSION['ADMINISTRATOR'])){
    15.         header('Location: /administrator.php');
    16.     } else {
    17.     $title = "";
    18.     $description = "";
    19.     $keywords = "";
    20.     $content = "<form action='/administrator.php' method='POST' name='' id=''><input required type='text' name='entLogin' id='entLogin' placeholder='' maxlength='40'><input required type='password' name='passwd' id='passwd' placeholder='' maxlength='40'><input type='submit' value='Войти' name='adminSubmit' id='adminSubmit'></form>";
    21.     }
    22. break;
    23.  
    24. default:
    25.     http_response_code(404);
    26.     $title = "";
    27.     $content = "<h1>Ошибка 404</h1><p style='text-align:center;'>Такой страницы не существует</p>";
    28. break;
    29. }
    30. ?>
    31. <!DOCTYPE html>
    32. <html>
    33. <head></head>
    34. <body>
    35.     <?= $content ?>
    36. </body>
    37. </html>
    administrator.php:
    PHP:
    1. <?php
    2. require_once("config.php");
    3.  
    4. switch($_SERVER["REQUEST_URI"]){
    5. case "/administrator/":
    6.     $title = "";
    7.     $content = "";
    8. break;
    9. case "/administrator/remont/":
    10.     $title = "";
    11.     $content = "";
    12. break;
    13. }
    14.  
    15. if (isset($_POST['adminSubmit'])){
    16.     if($_POST['entLogin'] == "" && md5($_POST['passwd']) == ""){
    17.         $_SESSION['ADMINISTRATOR'] = 1;
    18.         echo $content;
    19.     } else {
    20.         echo "<p style='text-align:center; margin:50px;'>Ошибка входа</p>";
    21.     }
    22. } elseif (isset($_SESSION['ADMINISTRATOR'])){
    23.     echo $content;
    24. } else {
    25.     header('Location: /');
    26. }
    27. ?>
     
  2. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.840
    Симпатии:
    1.338
    Адрес:
    Лень
  3. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @MouseZver, я потому и спрашиваю. Ваш ответ полностью бесполезный.
     
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Ну сам подобный "роутинг" не сломают. Но на серьёзный сайт это конечно не ставится. Для обучения пойдёт. В принципе, любой роутинг будет проверять $_SERVER["REQUEST_URI"], но не столь примитивным способом
     
  5. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @mkramer, извините, не очень понял. Точнее говоря, совсем не понял. Что значит "роутинг"? То, что я написал на странице administrator.php switch($_SERVER["REQUEST_URI"]) - это у меня не работает, так как вся эта работа выполняется уже в index.php. А написал я его для того, чтобы показать, как бы я хотел сделать (то есть не разделить все страницы зоны администратора на множество файлов, а сделать всё аккуратно на одном файле - administrator.php). Конечно, зону администратора можно сделать и на файле index.php, но я хотел бы администраторскую зону отделить и написать в другом файле.

    А вход в админ. зону по логину/паролю, создание сессии - это я делаю для достаточно серьёзного сайта, не для обучения - там будут храниться данные клиентов, которые оставляют мне свою технику на ремонт. Не могли бы подсказать, как правильно и безопасно это сделать либо сообщить ссылку, где я мог бы получить такую информацию (желательно написанную для "программистов" моего уровня)?
     
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Роутингом называется определение по REQUEST_URI части программы, которая будет выполняться. Вот этот твой свитч.

    Не, для серьёзного сайта это не сильно пойдёт :)

    В принципе, в PHP два основных подхода - либо под каждую страничку делается свой PHP файл (устаревший, но рабочий подход). С тем уровнем знаний, которые ты показываешь, может и лучше будет, поскольку там всё достаточно просто.

    Либо единая точка входа (вcе запросы кидают средствами веб-сервера на index.php), которая уже дальше разбирается, какие файлы выполнять. Но опять же, не в одном всё файле лепится, конечно. И не простым свитчем, а что-нибудь поинтереснее. Например, создать массив с ключами - роутами, а значениями - именами файлов, которые будешь включать. Что-то вроде
    PHP:
    1. $routes = ["a" => "a.php", "b" => "b.php"]; // Хорошо бы тоже вынести в отдельный файл
    2.  
    3. // Пропускаем URI через parse_url, чтоб нам гет-параметры не мешались
    4. $routePath = parse_url($_SERVER['REQUEST_URI"], PHP_URL_PATH);
    5.  
    6. if ($routes[$routePath] ?? false) {
    7.    require(__DIR__ . '/pages/' . $routes[$routePath]);
    8. } else {
    9.    require(__DIR__ . '/pages/404.php');
    10. }
    Ну это так, примерно. А вообще, повысить уровень, и использовать что-то нормальное, например https://route.thephpleague.com/, или какой-нибудь фреймворк маломальский, типа слима.
     
    #6 mkramer, 9 апр 2023
    Последнее редактирование: 9 апр 2023
    artoodetoo и Булат Азат улы нравится это.
  7. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @mkramer, понял, спасибо большое! Код понравился, переделаю свой сайт на него. Но возник вопрос. Чтобы это
    PHP:
    1. $routes = ["a" => "a.php", "b" => "b.php"];
    не писать и не дописывать туда каждый раз, когда добавляются новые страницы, правильно ли будет, если вместо этого кода получить список файлов в папке pages в массив и разово убрать у них окончание .php?
    И как правильно поступить, когда url - корень страницы? Добавить ещё одно условие на if ($routePath == "/") ?
     
  8. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    Да можно по-разному, дописывания роутов помогает, в принципе, потому что название роута и файла тогда могут не совпадать (а если они, как у меня, совпадают, на самом деле, может и не нужна единая точка входа). Можно в принципе динамически имя файла формировать из маршрута, но там труднее сделать это безопасно.

    В общем и целом, я, конечно, никогда в реальных программах такое не использовал. Даже когда работал с InstantCMS, в которой по дефолту, в качестве роутинга предлагалось как раз писать огромную функцию со свитчем (раньше, сейчас может получше стало, я лет 8 наверное уже не имел с ней дело), я на уровне своего компонента переходил на создание контроллеров, как во фреймворках.
     
    Булат Азат улы нравится это.
  9. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @mkramer, спасибо вам большое за помощь!
     
  10. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.199
    Симпатии:
    183
    @Булат Азат улы md5 не рекомендуют использовать, вместо неё, лучше использовать password-verify

    Можно ещё куку добавить с HttpOnly, а не только сессию.
     
    Булат Азат улы нравится это.
  11. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.861
    Симпатии:
    656
    Админку можно сделать на отдельном (под)домене, чтобы не разбавлять фронт-контроллер левой точкой входа. Можно и в ветке "/administrator/" через единый фронт. Только безо всяких 'Location: /administrator.php' – это же публичный адрес, его в принципе быть не должно (т.е. доступности файла по такому адресу).

    Белый список нужен. Ассоциативный массив в коде позволяет выполнять быстрый поиск по списку. Загружать на каждый чих полный список накладно (представьте, что он очень большой). Можно делать роутинг по БД.

    Это ламерский подход. Вам же показали, что первый слеш «отсекается»! И что в итоге остается? Правильно, пустая строка – вполне себе ключ для ассоциативного массива и т.п.

    Зы: Простая модель для «чайников»
     
    Булат Азат улы нравится это.
  12. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @Dimon2x, спасибо за совет! Переделаю на password-verify.
    @miketomlin, у меня ещё в форме ввода логина и пароля указан этот файл - "form action='/administrator.php'". Не могли бы подсказать, как правильно или сообщить ссылку, где можно получить такую информацию?
     
  13. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.861
    Симпатии:
    656
    Правильно – забыть про имена php-файлов в адресах, как про страшный сон. Их не то что в адресах быть не должно, к ним не должно быть прямого доступа. Сейчас любой вменяемый хостинг позволяет убрать их из корня. Это самый простой и надежный способ защиты. В корне максимум оставляете фронт (index.php). Причем фронт обычно по /index.php[?query] выдает 404-ую.

    Адреса для динамика используете только «виртуальные», например /administrator[/].
     
    Булат Азат улы нравится это.
  14. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.861
    Симпатии:
    656
    См., повторять /administrator/ в роутах не обязательно. Можно сделать иерархическое описание, т.е. описать родителя "administrator" с потомками "" (пустая строка) и "remont".

    Зы: в Простой модели, о которой я писал в статье, можно даже «зациклить»:
    есть типа страницы g09.ru/, g09.ru/page, g09.ru/index.html и т.п.
    и есть типа админка в ветке /pages[/] (pages – спец. запись, ссылающаяся на отдельные записи той же таблицы через представление БД), делающая такое: g09.ru/pages[/], g09.ru/pages/page, g09.ru/pages/index.html и т.п.
    --- Добавлено ---
    В БД:
    Код (Text):
    1. INSERT INTO `site_categories` (`id`, `name`, `content`, `module`, `bits`) VALUES
    2. ('', 'Home', '<h1>It works!</h1>\r\n<p>This is a home page.</p>...', '', 48),
    3. ('index.html', 'Иллюзия присутствия', '<p>Такого файла не существует. Вам это только кажется )))</p>', '', 0),
    4. ('page', 'Заголовок страницы', '<p>Содержание страницы</p>', '', 16),
    5. ('pages', 'Страницы', '', '', 19);
    При «обычном» роутинге для зацикливания вместо жесткой привязки на уровне БД вы просто «говорите» роутеру, что у pages есть потомки, в результате чего соотв. контроллер сам ищет потомков.
     
    #14 miketomlin, 11 апр 2023
    Последнее редактирование: 11 апр 2023
    Булат Азат улы нравится это.
  15. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @miketomlin, а как убрать ссылку на PHP-файл с формы входа в админку (ввода логина/пароля)? Там же, как я знаю, вроде всё равно нужно писать ссылку на файл-обработчик?
    HTML:
    1. <form action='/administrator.php' method='POST'><input type='text'><input type='password'><input type='submit'></form>
     
  16. Булат Азат улы

    Булат Азат улы Активный пользователь

    С нами с:
    31 авг 2017
    Сообщения:
    61
    Симпатии:
    6
    Адрес:
    Республика Татарстан, город Казань
    @miketomlin, прошу прощения, немного затупил. Там же тоже можно написать /administrator/ :)
     
    miketomlin нравится это.