Концепт защиты PHP сайта

24 комментария

Все мы, так или иначе, хотели бы быть уверенны в том, что наш сайт или блог никто не сможет взломать. Но увы, реальность такова, что любая система уязвима, как бы сильна она не была бы защищена. Все упирается лишь в ресурсы и в упорство взломщика… Хм… Что то меня не туда потянуло… Будем считать это предисловием =)

Не так давно я писал о том как правильно загружать файлы на сервер. Но допустим вы взяли уже готовую CMS и не знаете, как там реализованна загрузка, да и вобще вся защита. Конечно, особо пытливые и грамотные разработчики изучат код этой цмс прежде чем поставят на свой сайт. Но что делать тем у кого нет столько времени?

Хорошо, или допустим вы из тех кто считает что безопасность и правильная настройка сервера лишней не бывает? Если так то добро пожаловать под кат.

Нет, в статье вы не найдете какой-то супер пупер плагин, фильтрующий все данные, который нужно приинклудить ко всем файлам. Моя идея заключается в использовании директивы auto_prepend_file и постройки списка разрешенных файлов… Но в общем читайте сами…

Данная идея у меня давно сидела в голове, но наконец у меня дошли руки, хоть ничего сложного тут и нету, и я смог эту систему реализовать и написать статью =)

Принцип работы

Как я уже говорил выше, система основанна на работе директивы auto_prepend_file в php.ini. Отвечает она за установку скрипта, который будет выполнятся ПЕРЕД выполнением основного.

К примеру вы открыли index.php, а перед его выполнением запускается файл, указанный в auto_prepend_file. Суть в том, что в этом скрипте мы сможем контролировать дальнейшую работу остальных скриптов. Грубо говоря, продолжить работу и запустить запрошенный скрипт, или завершиться сразу (die()).

К примеру ситуация — злоумышленник залил на ваш сайт шелл через какую нибудь уязвимость и пытается его открыть в браузере. А вместо его шелла, ему, без всяких на то причин, отдается, вот такая вот ошибка:
403_forbidden
Меня бы подобное ввело бы в ступор…

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

Diagram_first

(Не знаю нужна ли эта диаграмма, вроде бы и так все должно быть понятно…)

Конечно составлять такой список вручную — дело не благородное, поэтому я пришел к выводу, что имеет смысл реализовать так называемый «режим обучения». Режим в котором все обращения ко всем скриптам будут заносится в список разрешенных файлов автоматически.

Diagram_second

Что это дает? Вы можете запустить эту систему в режиме обучения и продолжить пользоваться своим сайтом. По мере того как вы будете им пользоваться, ваша база будет пополнятся теми страницами, которыми вы пользуетесь (простите за каламбур). И допустим через месяц — другой у вас в списке будут содержаться все файлы которые имеют отношение к вашему сайту (к которым вы непосредственно обращались).

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

Что умеем

Так как это концепт, то и умеем мы не много.

  • Блокирование неразрешенных скриптов (собственно основная функция). Но опять же это настраиваемо, можно не блокировать соединение, а только лишь уведомлять админа по email
  • Уведомление о нелегитимных запросах администратору по email (краткий отчет или полный отчет, последний включает заголовки пакета и данные POST запроса если таковые имеются)
  • Можно указать IP администратора, который будет иметь доступ к любым скриптам, т.е. данная система его затрагивать не будет (эти IP не будут участвовать в режиме обучения). К примеру теперь не надо закрывать .htaccess-ом софтины типа PhpMyAdmin, SupexDumper и прочие системные утилиты.
  • Ксати Ip адреса поддерживают простенькие маски=)
  • Полностью прокомментированный код, и подробно описанна каждая директива конфигурации
  • Хз что еще…

Настройка

Теперь о том как встроить эту защиту в ваш сайт…

Для этого вам необходим доступ к файлу php.ini

  1. Для начала скачиваем сам скрипт: PrependSecuritySystem
  2. Распаковываем содержимое архива (data.txt и main.php) в какую либо папку на сервере, желательно в папку не доступную из веба (не обязательно, т.к. работать будет в любой, это имеет смысл чтобы убрать скрипт подальше от глаз взломщика)
  3. Открываем файл main.php и редактируем настройки. Необходимо обязательно поменять ip адрес и email админа. Остальные настройки же — по вашему желанию.
  4. Устанавливаем права доступа к распакованным файлам. Под никсами желательно изменить владельца для обоих файлов, отличного от пользователя из под которого работает веб сервер. Для файла main.php необходимо запретить запись для всех. Для файла data.txt необходимо установить права на чтение и на запись для всех (это временно, на период обучения)
  5. Открываем php.ini и вписываем следующее:
    auto_prepend_file=[путь до распакованного файла main.php]
  6. С данного момента начинается обучение системы. Выжидаем определенное колличество времени, достаточное, по вашему мнению, для полного обучения данной системы.
  7. По окончанию обучения открываем файл main.php и редактируем костанту PSS_STATUS_BLOCK, устанавливаем ее значение в true, сохраняем
  8. Изменяем права доступа на файл data.txt. Запрещаем редактирование данного файла для всех.
  9. Теперь система перешла в режим блокирования неразрешенных скриптов

Многовато шагов, конечно, но с этим, как мне кажется, справится даже ребенок.

Если вам необходимо переобучить систему (с нуля или дополнить), то вам необходимо:

  1. Разрешить запись в файл data.txt
  2. Очистить содержимое data.txt (ТОЛЬКО если вам необходимо переобучить систему с нуля)
  3. Отредактировать костанту PSS_STATUS_BLOCK в файле main.php, установив ее значение в false
  4. Проводим переобучение…
  5. По окончанию переобучения редактируем константу PSS_STATUS_BLOCK устанавливая ее значение обратно в true
  6. Запрещаем запись файла data.txt

Ну а теперь о грустном

Лукавить я не буду, и теперь расскажу о недостатках.

  • Пожалуй главный недостаток по сравнению с которым меркнут все остальные, это то, что эту систему можно обойти. Вы спросите: как же так? Все очень просто, директиву auto_prepend_file можно указать и в .htaccess. И если подойти трезво то если злоумышленник вдруг смог залить шелл, то наверняка он сможет залить и свой .htaccess в котором он может отключить оригинальную директиву.
    Это работает только под apache, но к примеру под nginx этот трюк не выйдет (у nginx нет файлов .htaccess). НО! Под Nginx можно вообще залить свой php.ini в любую папку и в этой папке будут действовать новые директивы.
  • Злоумышленник может отредактировать «разрешенный» скрипт если есть допустимые права на это, и с этим наша система ничего, к сожалению, сделать не сможет. Разве что необходимо устанавливать правильные права на все исполнемые файлы
  • Помимо PHP есть еще всякие perl, cgi и прочее… с ними данная система не работает.
  • Дополнительная нагрузка. Но вртяли эта нагрузка будет ощутима.

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

Заключение

Все же, так или иначе, это концепт, может быть вы сможете придумать на ее основе что то лучшее. А может быть вас устроит моя система.

На мой взгляд разумной защиты много не бывает. Использовать что-либо подобное или нет, у вас на сайтах решать вам.

Фуф. Ну и написал я, почти целый день ушел. Простите если описал несколько сумбурно. В общем задавайте ваши вопросы в комментариях, я постараюсь ответить.

PS: хоть я и кодил максимально адекватно, скрипт может иметь баги. Тестировалось на win/apache/php 5.2 — все было ок.

UPD: запилил репозиторий на гитхабе: https://github.com/InSys/PrependSecuritySystem

  1. mr.The

    Отличная идея, кроме этого, можно напрямую контролировать содержимое, например $_FILES, и не давать заливать файлы с неподходящими расширениями.

    И да, выложи скрипт на гитхаб, будет очень удобно)
    Или хоть в .zip перепакуй, а то rar это совсем не по феншую.

    1. Дмитрий Амиров Автор

      Сорри, на гитхабе меня нету (не смейтесь, плиз), но да с rar-ом я что то перегнул… Перезалил архив в zip. Спасибо =)

    2. Дмитрий Амиров Автор

      Касательно проверки _FILES… На мой взгляд не совсем удачная идея — я стараюсь кодить так чтобы было разрешенно заливать любое расширение (ну если это не загрузка картинки).

      К примеру — у вас какой нить форум кодеров, и кто-то хочет прикрепить в тему файл script.php, не запрещать же ему это делать? Решение простое — оригинальное имя с расширением заносим в БД, а сам файл переименовываем вместе с расширением и сохраняем под новым именем.

      Хотя, да, можно сделать топорно — запретить загрузку файлов «php.ini» и «.htaccess» и скрипт не смогут отключить =)

      1. mr.The

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

        пс. заведи себе гитхаб, шикарная же штука)

        1. Дмитрий Амиров Автор

          Пожалуй да, своим задачам — свои инструменты :)

          А насчет гитхаба — заведу в ближайшем обозримом будущем, как руки дойдут)

  2. Антон

    Интересный метод :) Один момент только:

    Пожалуй главный недостаток по сравнению с которым меркнут все остальные, это то, что эту систему можно обойти. Вы спросите: как же так? Все очень просто, директиву auto_prepend_file можно указать и в .htaccess. И если подойти трезво то если злоумышленник вдруг смог залить шелл, то наверняка он сможет залить и свой .htaccess в котором он может отключить оригинальную директиву.
    Это работает только под apache, но к примеру под nginx этот трюк не выйдет (у nginx нет файлов .htaccess). НО! Под Nginx можно вообще залить свой php.ini в любую папку и в этой папке будут действовать новые директивы.

    Изменение директив через .htaccess действует только когда php подключён к Apache как его модуль (mod_php). В иных случаях (cgi, fcgi) .htaccess для PHP бесполезен.
    А изменение директив через находящийся в папке скрипта php.ini возможен и на Apache, но только в режиме работы PHP cgi/fcgi. + эта функция во всех веб-серверах регулируется через конифиги. То есть можно попросту отключить «просмотр» левых php.ini

    1. Дмитрий Амиров Автор

      А изменение директив через находящийся в папке скрипта php.ini возможен и на Apache, но только в режиме работы PHP cgi/fcgi.

      Я это и имел ввиду, пожалуй, не совсем ясно выразился (эту часть статьи я дописывал уже где то в два часа ночи). Я писал уже статью на эту тему недавно.

      Имелось в виду то, что эту защиту можно обойти залив либо .htaccess либо php.ini в зависимости от конфигурации сервера.

      эта функция во всех веб-серверах регулируется через конифиги. То есть можно попросту отключить «просмотр» левых php.ini

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

      1. Антон

        По поводу запрета загрузки php.ini — сейчас посмотрел бегло, но рецепта готового не откопал. Попробуй спроси на форумах типа linuxforum или unix-forum. Такое точно возможно т.к. сам ни раз встречал на хостингах.

        1. Дмитрий Амиров Автор

          Чесно говоря, у меня уже у самого появилась идея. Но надо поднять вебсервер для тестов, все никак руки не дойдут.
          Но все равно спасибо Вам за суету =)

    1. Дмитрий Амиров Автор

      Врятли нынче какой то среднестатистический сайт работающий под апачем может обойтись без .htaccess. Разве что резрешить только корневой htaccess как то так:

      #Разрешаем корневой htaccess
      &#60Directory /home/public_html/&#62
      AllowOverride All
      &#60/Directory&#62

      #Запрещаем htacess-ы лежащие в каталогах глубже
      &#60Directory /home/public_html/*&#62
      AllowOverride None
      &#60/Directory&#62

      (С конкретным синтаксисом могу ошибаться). Но это доставляет неудобство вплане необходимости настройки httpd.conf, ну и мало ли вдруг ваш сайт использует htaccess в других папках.

      Но хотя, да, идея не плоха.

  3. Hammer

    Что произойдёт, если будет попытка атаки во время обучения? Не посчитает ли программа что это нормальное действие и запишет ли в каталог файлов как разрешённые?

    1. Дмитрий Амиров Автор

      Запишет, поэтому во время обучения нужно быть предельно внимательным. С этим, к сожалению, ничего не поделаешь. Ну или как вариант — обучать вручную.

        1. Hammer

          и раз уж на самый пожарный лучше вручную, то подскажите, а то сомневаюсь. К примеру ссылка index.html хотя на самом деле фаил index.php, ну и index.php?id=10, index.php?id=5(/index/10.html, /index/5.html) имеет ли значение?

          1. Дмитрий Амиров Автор

            Боюсь что я не смогу вам подсказать. С момента написания поста и этого скрипта прошло уже больше года. Я не помню деталей реализации, вам прийдется вникнуть в них самому(

            1. Hammer

              а если убрать хеширование названия файлов, сыграет это роль на безопасность, сам скрипт и БД лежат, вне корня сайта?

              1. Дмитрий Амиров Автор

                Хеширование? Напомните пожалуйста, где там используется хеширование

            2. Hammer

              Убрал хэширование и вижу что номера в ссылках не играют роль, файлы определяются правильно.

  4. Мимопроходил

    Собственно, заглянул случайно на этот сайт — да тут и остался… Добавил в закладки.
    Что касается использования директивы «auto_prepend_file», то ведь её и необязательно использовать в качестве «меры защиты». Это очень вкусная директива, по поводу и без оного.
    Но возникают сомнения — сильно ли это отличается от прямого указания «require/include» в каждом запускном файле? (помимо незначительного увеличения кода, естественно)

    1. Дмитрий Амиров Автор

      Понаписали вы конечно мне комментариев) Сейчас постараюсь на все ответить.

      Насчет

      Но возникают сомнения — сильно ли это отличается от прямого указания «require/include» в каждом запускном файле? (помимо незначительного увеличения кода, естественно)

      вы правы, разницы нет между auto_prepend и подключением оного в каждый скрипт. Но вот если все же использовать в качестве меры защиты — то только auto_prepend т.к. нужно чтобы этот скрипт выполнялся для всех php скриптов на сервере (Врятли злоумышленник будет подключать систему защиты через include в свой веб шелл :D ).

Добавить комментарий

Прочли запись? Понравилась? Не стесняйтесь, оставьте, пожалуйста, свой комментарий. Мне очень интересно, что вы думаете об этом. Кстати в комментарии вы можете задать мне любой вопрос. Я обязательно отвечу.

Вы можете оставить коментарий анонимно, для этого можно не указывать Имя и email. Все комментарии проходят модерацию, поэтому ваш комментарий появится не сразу.