Pull to refresh

Борьба с «плохими» URI, спамерами и php-шеллами — личный опыт

Reading time 11 min
Views 17K
Полагаю, все веб-программисты проходят в той или иной степени одинаковый путь. Я основываюсь на своем личном опыте. Для меня в начале постижения этой науки создание сайта было на первом месте. Только по прошествии значительного времени я осознал, что сайты еще и вскрывают. Прочитав, как это делается, я удивился, на сколько просто по неопытности превратить свой сайт в «проходной двор» и стал уделять безопасности определенное внимание. По крайней мере я стал фильтровать входные параметры страниц.

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

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

Что же нужно иметь ввиду и что можно сделать для создания относительно безопасного сайта?

Стоит ли располагать файлы разных типов в отдельных папках?


Современный сайт, созданный на PHP, имеет обычно довольно разветвленную файловую структуру. В ней однозначно есть исполняемые скрипты, модули или классы, подключаемые инструкцией include/require, файлы .css и .js, страничный кэш. Вот этими файлами для простоты и ограничимся.

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

Deny from all

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

Deny from all
<FilesMatch "\.js$">
    Allow from all
</FilesMatch>

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

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

Стоит ли называть папки нестандартным образом?


Вот, кстати, хороший метод реально повысить безопасность своего сайта. Дело в том, что вредоносный робот ищет на сайте папки с определенными названиями. Это же относится и к файлам. Поэтому как одна из мер повышения безопасности — это изменение имен папок и файлов на что-то нестандартное. Стоит придумать что-то свое и дать именам хотя бы префиксы. Префиксы однозначно помогут от роботов. Если хотите попробовать затруднить и ручной взлом, то советую пойти дальше и дать папкам и основным файлам имена собственные (Петя, Маша и т.д.). Не многие молодые хакеры будут разбираться, где что у вас лежит. Хотя у хакеров, занимающихся взломом от скуки, не известно, какая каша может быть в голове. Но шанс, определенно есть! Главное самому не запутаться. Тоже шанс немалый.

Файл config.php, в котором лежит пароль доступа к базе данных в открытом виде


Вот это то, чего я никак не могу понять. Есть файл, который все знают, как называется, и в котором в открытом виде лежит именно то, что нужно хакеру. Зачем это делается? Это, на мой взгляд, вредительство какое-то. Крайне рекомендую на всех своих сайтах зашифровать данные для доступа к базе данных и разместить их в совершенно нестандартно названном файле, закрытом от доступа по сети и доступного только для чтения. Конечно, надо поработать над оптимизацией скорости расшифровки, но это тоже вполне решаемо. По крайней мере XOR действует довольно быстро (ссылка на Шифр Вернама в конце статьи). Главное иметь ключ хорошей длины и получше его спрятать. Можно создать действительно запутанный и очень эффективный алгоритм расшифровки и заставить хакера провести на вашем сайте много часов, прежде чем им будет найден и ключ и алгоритм его использования. Вы же вовремя злонамеренную деятельность видите, благодаря вашей собственной системе логирования-оповещения, пресекаете деятельность злоумышленника и меняете ключи, пароли, явки и так далее. Поэтому скачивать ваши скрипты и разбираться с ними до потери сознания для хакера может оказаться непродуктивным.

Безопасность запускаемых скриптов php


Очень важная тема. В первую очередь скажу, что публичный хостинг действительно могут вскрыть и на вашем сайте откуда ни возьмись окажется файл с условным названием template.php. Предположим, что ваша замечательная система логирования и оповещения через какое-то время, например, через 10 минут, определит появление в такой-то папке такого-то нового файла и пришлет вам об этом письмо. Казалось бы замечательно! Но шелл может за 10 минут такого на сайте натворить, что сайт на несколько часов выйдет в аут. Проходили. Знаем, о чем говорим.

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

<?php
echo 'hi!'; 

Далее разместите его в корне своего сайта на WordPress и вызовите его (скрипт). И он скорее всего сработает! Покажет вам ваш привет!

Вот какая эволюция методов борьбы с этим злом происходила у меня. Но я не работаю на бесплатных (и платных) движках и мне легче!

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

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

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

Мы удаляем из .htaccess все правила урл-рерайтинга, которые там были и оставляем только одно правило, которое любой файл отправляет на один разъединственный исполняемый скрипт вашего сайта. Он имеет особое, ни на что не похожее название, как минимум префикс. Этот скрипт по REQUEST_URI разбирается, что же это пришло, делает всякие seo-действия по рерайтингу и решает, на какой скрипт передавать управление. Управление передается не рерайтингом, конечно, а путем подключения файла инструкцией require. В итоге доступ на вашем сайте разрешен всем, но выполняется всего один исполняемый php-скрипт. Все остальные скрипты лежат в отдельной папочке и защищены от запросов по сети и могут быть защищены инструкцией Deny from all. А могут и не быть.

Кстати, такая схема употребляется в некоторых движках. Но там всем управляет мега-скрипт index.php с 10 тысячами строк и более, и реализована эта схема вовсе не ради безопасности, а для того, чтобы было удобнее закрыть код от разворовывания.

Вот такое правило стоит у меня в .htaccess

RewriteCond %{REQUEST_URI} !^/sitemap\.xml$
RewriteCond %{REQUEST_URI} !^/favicon\.ico$
RewriteCond %{REQUEST_URI} !^/apple-touch-icon(?:\-precomposed)?\.png$
RewriteCond %{REQUEST_URI} !^/robots\.txt$
RewriteCond %{REQUEST_URI} !^/pref_dispatch\.php$
RewriteRule ^.*$ /pref_dispatch.php [L]


Обратите внимание, что пропускаем мы совершенно определенные файлы, которые у нас точно существуют, и на диспетчерский скрипт переводятся все запросы без исключения, а не одни только скрипты php. Кстати, можно и robots.txt, и sitemap.xml генерировать в диспетчере и отдавать, как скрипт. А можно и картинки…

Что происходит с урлом, который не проходит проверку в диспетчере?

Он записывается в "лог плохих ури". Этот лог я изредка просматриваю для того, чтобы определить, не запрещен ли у меня какой-либо нужный ури, и не нужно ли сделать переадресацию. Лог плохих ури зарекомендовал себя как один из самых полезных и занимательных инструментов в админке. Сразу видно кто ломится, куда ломится, и что, вообще, на сегодня интересно хакерам. Конечно, на первом месте стоит wp-admin и wp-config. Есть о чем задуматься любителям бесплатных движков.

Как сделать так, чтобы плохие ури собирались со всех папок, а не только с корня сайта?

В лог плохих ури попадают ури вида /very-bad-uri-script.php или /very-bad-uri-folder/. Но если ури имеет вид типа /existent-folder/very-bad-uri-folder/, этот ури в лог может и не попасть. При этом в лучшем случае в логе ошибок мы увидим строку типа File does not exist: /existent-folder/very-bad-uri-folder/

Если мы для папки /existent-folder отключили все для всех, то будет ошибка типа client denied by server configuration.

И то и другое не очень удобно. Дело в том, что вызов, попадающий в лог ошибок, уже не попадает в лог доступа, и мы не увидим никаких подробностей. Самое неприятное, что мы не получим никакого письма в случае подозрительной активности на сайте. Такая неприятность происходит из-за того, что в папке /existent-folder либо вообще отсутствует файл .htaccess, либо в нем не включен урл-рерайтинг. Для того, чтобы этого не происходило нам надо во-первых, разрешить доступ к этой папке всех, то есть стереть нашу строчку Deny From All, а во-вторых, включить урл-рерайтинг.

RewriteEngine on
RewriteBase /

RewriteRule ^.*$  /badurl/ [L]

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

Вышеприведенный .htaccess подходит для замены функциональности "Deny from all". В случае, если нам надо что-то пропустить, например, скрипты js или таблицу стилей, то нужно либо разрешить запрос определенных типов файлов, либо, что лучше, задать скриптам особые имена или префиксы. Ну, или перечислить пропускаемые файлы явно. Но, боюсь, это уже слишком жестко в смысле продуктивности и программиста и сервера.

Атаки и блокирование вредоносных IP


Время от времени, но с удивительной регулярностью, на сайт происходят атаки. Среди этих атак есть такие, когда с определенного IP идут прозвоны страниц логина и регистрации пользователя, отправки писем через форму и приема объявлений. Это работают mail-сервера. Работают они чаще всего в паре с «чистыми» IP, которые не используются для атак, а используются только для прозвонов. Для определения сущности IP, занимающихся спамом, я сам использую и всячески пропагандирую сайт projecthoneypot.org.

Бороться с такими спаммерами оказалось крайне просто. Надо просто реализовать все эти формы аяксом и все. Одного только этого бывает уже вполне достаточно. Для пущей безопасности можно запретить вызов php-бэкенда, если он не идет с сайта.

Очень объемный трафик идет от сомнительных ботов. Почему сомнительных? Потому что я не знаю, полезны ли эти боты для сайта и зачем они ходят по моему сайту и звонят урлы, которые вышли из употребления много лет назад. Вообще, появление давным давно убитых урлов само по себе является компрометирующим действием для бота. Такие боты чаще всего не используют файл robots.txt или используют его в противоположном направлении, то есть для них существование списка запрещенных к просмотру адресов есть повод именно до них и ломиться. Тем не менее, эти боты честно метят себя в пользовательских агентах. Из таких я могу назвать 199.192.207.146 с агентом
Mozilla/5.0 (compatible; MJ12bot/v1.4.5; http://www.majestic12.co.uk/bot.php?+)
или 185.53.44.90 с агентом
Mozilla/5.0 (compatible; XoviBot/2.0; +http://www.xovibot.net/)
IP в приведенных выше примерах реальные, но понятно, что у этих ботов не один IP адрес, а много.

Есть и боты, маскирующиеся под хорошие, но, похоже, такими не являющиеся. Вот, например, 176.31.182.56 с агентом
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
По действию этого IP на моем сайте у меня есть очень большие сомнения, что это действительно Googlebot.

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

Но есть атаки не направленные явно на спам. Запросы могут сыпаться со скоростью несколько штук в секунду и представляют собой полную чушь. Часто испорченные и исковерканные запросы к самому сайту, а часто атаки на движки, из которых лидирует WP. Серия запросов обычно может быть от 100 до 200 штук в одной серии за сутки. Зачем ломиться до движков — понятно, наверное. Зачем пытаться добиться ответа сайта по исковерканным и часто вообще нечитаемым урлам мне не понятно. Но факт в том, что куча запросов с высокой скоростью замедляют и сам сайт и его соседей по хостингу и с ними стоит бороться.

Кстати, что такое «нечитаемый урл»? А вот что!

http://мой-сайт.ru/bulletin_board/ad_add/+++++++++++++++++++++++++++++++++++++Result:+%ED%E5+%ED%E0%F8%EB%EE%F1%FC+%F4%EE%F0%EC%FB+%E4%EB%FF+%F0%E0%E7%EC%E5%F9%E5%ED%E8%FF;+Result:+%ED%E5+%ED%E0%F8%EB%EE%F1%FC+%F4%EE%F0%EC%FB+%E4%EB%FF+%F0%E0%E7%EC%E5%F9%E5%ED%E8_cutted

Пожалуйста, не пытайтесь реально зайти по этому урлу на мой сайт, ибо в этом случае ваш IP будет помечен опасным и он будет поражен в правах.

Во-первых, урл имеет длину боле 255 знаков и его пришлось обрезать. Во-вторых, хоть все, что идет за словом «Result:» и декодируется (windows 1251), но все равно представляет собой чушь. Есть подозрение, что запрашивает этот урл XoviBot/2.0, причем в сравнительно больших количествах и всегда одинаковый.

Но как бороться? И стоит ли блокировать все подряд? Если с этим процессом трудно бороться, может быть его можно возглавить, или как-то по-другому к нему приспособиться?

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

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

При заходе с заблокированного IP клиент попадает на специальную страницу, где ему предлагается нажать на кнопку и разблокировать IP. Кнопка аяксовая. Запись о блокировке автоматически меняется на «разблокированный IP». У меня сейчас порядка 20 заблокированных IP. Был ли хоть один из них разблокирован пользователем? Нет. Не был. Часто происходят заходы с уже заблокированных IP? Нет, исчезающе редко.

Для всех клиентов, приходящих с IP, которые как-либо помечены, никогда не производится дополнительная обработка их запросов. Для них не проверяется наличие обязательного обратного слэша, они не проверяются на список редиректов, для них не работает преобразование SEO адресов. Если запросы не являются полностью хорошими, то им тут же, без задержки, выводится краткое прощанье.

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

Резюме


Выше описаны довольно простые действия, которые могут серьезно повысить степень защищенности любого сайта. У меня остается вопрос — почему же эти простейшие вещи не включены, кажется, ни в один движок? Ни в платный, ни в бесплатный?

Ссылки


Tags:
Hubs:
+6
Comments 89
Comments Comments 89

Articles