Pull to refresh

Comments 72

Имхо, но мне кажется такие вещи стоит делегировать на iptables(или аналог современее) и fail2ban, как минимум!

Между запросом и php проходит уйма событий и слоев, а это время и ресурсы.

Плюс, хотелось бы услышать профит возможно бенчмарки по использованию скопа echo, вместо единичного вызова.

Между запросом и php проходит уйма событий и слоев, а это время и ресурсы.

соглашусь полностью, задача DoS - забить канал, мера противодействия также должна быть уровнем как можно ниже, иначе мы даже облегчим задачу

в сторону отмечу, что для повышения устойчивости необходимо "срезать углы" на всех этапах:

  • клиентское кэширование: если можно обойтись без запроса на сервер, то лучше сервер не трогать

  • на сервере - сначала применить низкоуровневые проверки, те же iptables/fail2ban

  • затем применить то же кэширование, желательно на уровне прокси (тот же nginx и т.д.)

  • затем стараемся выполнить работу на уровне программного кода и памяти, не обращаясь к базе данных, файловой системе и другим "третьим лицам"

  • при обращении к ним также используем кэши (1,2, 3 уровней, ну вы знаете, для каждой платформы и базы данных свои)

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

отлично, если мы обходимся самым низким уровнем (к примеру, отдаём файлы серверным ПО, а не скриптом, тянуть такое добро из БД вообще имхо расточительно)

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

...но тем не менее, чем популярнее ресурс, тем (больше нагрузка) важнее минимизировать ресурсы, выделяемые на обработку запроса (не в ущерб безопасности и адекватности)

и с таких позиций реализация средств контроля доступа (таких низкоуровневых, как анти-ддос) на высоком уровне становится смехотворно непрактичной.

fail2ban тоже очень быстро начинает захлёбываться и получается отличный DoS

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


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

Спасибо за статью. Подскажите, не рассматривали ли вы готовые решения, например fail2ban?

Для блокировок по странам есть geoip_module в nginx если выносить на уровень веб-сервера, зачем делать этот слой на php?

на случай если сайт на хостинге простом а не на VDS

Тогда защита от ддос перекладывается на плечи хостера. Поднимать пхп со всеми модулями, чтобы проверить ip, ну такое. С таким же успехом можно грепать логи и заполнять .htaccess, но не по людски это.

"Обожаю" такие сайты: пытаешься открыть несколько вкладок, а оно тебя блочит по IP :)

Отвечу сразу на первые комментарии:

fail2ban реализуется средствами сервера, а доступ как правило есть не всегда - например хостинг не VPS/VDS, где вы не можете редактировать конфы и устанавливать доп.модули linux.

Что касаемо "скопа echo" - не важна реализация вывода, можно и одним exit или die заменить, просто для наглядности выводится мало-мальски оформленный в html текст. Скрипт очень быстрый, т.к. не вызывает никаких сторонних модулей и отрабатывает "в себе".

Данный скрипт - превентивная мера, нежели полноценная защита, и имеет место быть, как для познания, так и для использования, вреда точно от него нет :-)

" а доступ как правило есть не всегда - например хостинг VPS, где вы не можете редактировать конфы и устанавливать доп.модули linux."

Как раз наоборот, на VPS можете, это на шареде "нюансы".

- На шареде есть саппорт, это их задача и ниша, в крайнем случае, между доменом и шаредом подставляется ddos-guard/cloudflare, чья задача как раз в том, что бы "превентивно" отсеивать сомнительный трафик.
- Скоп echo не дает никакого профита, можно было оформить меньшим числом вызовов, что и стоило сделать, в виду "очень быстрый".
- Данный скрипт - излишняя мера усложнения, которая может быть уместна исключительно в вопросе изучения, но абсолютно не применима в реальных условиях.

В созидательных целях, материал приемлем, применять его, лично я, не советовал бы.

fail2ban реализуется средствами сервера, а доступ как правило есть не всегда - например хостинг не VPS/VDS, где вы не можете редактировать конфы и устанавливать доп.модули linux.

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

обычно бесплатный/дешевый хостинг несовместимы со "значимыми"/"серьезными" проектами. когда выйдете на новый уровень - у вас будут и эти проблемы, и деньги для их решения.

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

было решено — отсечь трафик не из России
Заходишь на такой сайт с VPN и ой… Знаете, а это даже хорошо. Поменьше будет посетителей у таких сайтов.
По существу — пробовал подобное решение. Справляется только со слабым DDoS. Для более плотного и разнообразного потока трафика лучше использовать низкоуровневые средства.

Нападает на крепость толпа зомбаков.
- крепостные ворота их пропустили
- по улицам пройти их пропустили
- в дом зайти им позволили
и вот тут уже в прихожей мы херачим их скалкой.

Может таки низкоуровневые атаки делегировать более низкому уровню?

Я конечно не php-шник, но мне кажется или для каждого заблокированного IP там создается отдельный файл? И соответственно это такой изощренный способ уложить не только веб-сервер, но и VPS\VDS целиком, тупо забив inodes любой сколько-нибудь серьезной DDoS-атакой с ботнета? Поправьте, плиз, если я ошибаюсь.

IP-адрес считывается из HTTP-заголовка Client-IP, так что даже ботнета не надо — с этим справится один простенький Python-скрипт в десяток-другой строк, подставляющий рандомные IP-адреса в заголовки запроса

Да, верно, для каждого ip создаётся файлик, и сам удаляется. Это с целью упрощения и не поднимая mysql, тогда бы сложнее было и дольше, как писали выше "несколько слоёв".

Любая серьёзная атака положит сервак нодами. А сам скрипт для небольших проектов, например ставлю на маленькие интернет-магазины или корп.порталы битрикс, чтобы на корню пресечь бота и не дёргать битрикс-ядро, которое само по себе тяжёлое.

Соответственно создав простым скриптом, [сарказм] даже на php [/сарказм] передав миллион запросов с фейковыми CLIENT_IP мы получим миллион файлов, чему безумно будет рад хостер в попытках забэкапить это, будет рад php (и апач с ним) в попытках удалить файлы, ну и по мелочам.

Скрипт удаляет старые файлы, созданные больше секунды назад (const intervalSeconds = 1), что несколько затрудняет создание миллиона файлов

UFO just landed and posted this here
было решено — отсечь трафик не из России

У нас была проблема после начала известных событий и трафиком не из России. Все проблемы решил iptables.

Не знаю и чего все так набросились. Как говориться - "все методы хороши".

на случай если сайт на хостинге простом а не на VDS

Поддерживаю.

$_SERVER["REMOTE_ADDR"] - единственный верный ip адрес.Все остальные которые клиент передает по своему усмотрению не в коем случае в расчёт принимать не нужно.

При схеме с балансером там может быть локальный ip сервера приложения вместо реального ip.

Только в случае, если у админа сервера кривые руки. Любую связку балансер/веб-сервер можно (и — разумеется — необходимо) настраивать так, чтобы в ней было четко указано — какой конкретно сервер и в каком конкретно заголовке имеет право передавать клиентский IP. Чтобы веб-сервер брал его строго оттуда, и уже внутри себя подменял им локальный. Иначе даже в аксесс логе самого веб-сервера будет локальный IP, то есть фактически бессмысленный мусор.


Разумеется, такая настройка не имеет ничего общего с той порнографией, которая используется в статье.

А по-моему прикольный костыль. Сам придумал, сам сделал, для конкретной задачи подходит. Не рационально, но и пусть. На то он и костыль.
Защита от DDOS, парсинга и ботов на PHP.

Первая буква D в слове DDOS означает распределённая. То есть нагрузка идёт с разных IP. И данный скрипт будет только ухудшать ситуацию, добавляя к потерям производительности от собственно атаки еще и потери на перебор и удаление миллиона файлов при каждом запросе.
Эффективно бороться с DDOS можно только на уровне провайдера. Делать это на уровне приложения — это тушить огонь бензином.
Не говоря уже о том, что его сайт никогда ни DDOS-у, ни просто DOS-у не подвергался. И у автора нет ни одного реального подтверждения того, что этот говнокод хоть от как-то защищает от атак на отказ в обслуживании.


От парсинга этот скрипт вообще не защищает, поскольку ему можно просто подсовывать новый рандомный IP адрес в НТТР запросе, не меняя реального хоста с которого идёт парсинг. А вот кому этот скрипт реально нагадит — это честным пользователям.
Плюс опять же увеличит нагрузку на пустом месте, создавая 100500 файлов для фейковых IP. В случае, если его реально начнут парсить.


Этот скрипт не защищает от DDOS, парсинга и ботов. Он защищает от влажных фантазий автора про "DDOS, парсинг и ботов".


Его идеи про то, что скрипт "работает" — это такие же фантазии. Всё что он видит в своих логах — это гребущие широким неводом скрипт-кидди, всё время разные, которые сканируют целые сети, и которым совершенно насрать на его сайт. И которые даже не подозревают, что этот сайт как-то там копошится у себя в ответ на их бездумное сканирование.


Вся эта история вообще не про защиту. Она укладывается в три строчки:


  • Посмотрел в логи, увидел много мусора. На работе сайта не отражается никак, но раздражает.
  • Написал какой-то код, разместил на сайте. Доволен, как слон
  • Посмотрел в логи, увидел много мусора. Разницы в работе сайта как не было, так и нет. Но раздражает уже не так сильно!

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

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

На первый взгляд скрипт полезен для хостингов, которые умеют отсекать DDoS, но не следят за ботами и не дают никаких низкоуровневых инструментов. Однако реализация не оптимальна, хотя бы потому что первой проверкой идёт определение "доброжелательности" бота по подстроке в UserAgent без всяких forward DNS lookup-ов или хотя бы белых списков IP. Слишком легко обходится. Неужели никто не встречал GoogleBot-ов, запущенных с серверов DO? Другие странные моменты и так уже расписали, повторять не буду.

Для шаред-хостинга, в принципе, такой скрипт (по концепции, а не этот) имеет право на жизнь, однако если есть возможность, лучше подключить что-то вроде https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker или вовсе поставить OpenLiteSpeed, который умеет отдавать капчу при попытках забросать сайт запросами.

Главное, что я не понял — так это смысл этого кода. Его предназначение.
Вначале говорится про логи веб-сервера. Но логи веб-сервера облагораживать на РНР глупо — запрос уже пришёл, в лог запись попала. Если уж чистить логи — то в конфиге веб-сервера.
Защита от взлома? Этот скрипт не занимается защитой от взлома. Не будем же мы всерьёз рассматривать скрипт-киддей, ищущих уордпресс?
DDOS — это конечно главная стратегическая ошибка автора. Если бы этого красивого и загадочного слова не было в заголовке, то читатели отнеслись бы к статье гораздо снисходительнее.
Остаются парсинг и боты. Я ОЧЕНЬ сильно сомневаюсь, что этот скрипт когда-либо применялся на сайте, который в реальности подвергается серьезным атакам ботов или пытается оберегать драгоценную информацию от парсинга. Просто потому что это конечно слёзы, а не защита.


В общем, с одной стороны — это неплохой код для джуниора (кто сам не выковыривал IP адрес из НТТР заголовков, пусть бросит в меня камень). И автора надо похвалить хотя бы просто за то что он задумал и реализовал такой проект.
Но с другой стороны — весь тот проект построен не на реальных потребностях, а на совершенно диких фантазиях, не имеющих ничего общего с реальностью. И это реальная проблема. Таких фантазёров, увы, сейчас много, люди отрываются от реальности и делают вещи, которые не имеют ни малейшего смысла. Такие симулякры.


Ну и пара чисто технических замечаний. В коде есть пара мест, от которых у меня сводит зубы. Про получение IP адреса уже написали 10 раз, на этом останавливаться не будем. Следующим по вредительству у нас идет цикл с перебором ВСЕХ файлов на каждый запрос. Я понимаю что нужна чистка мусора, но её-то надо как раз выносить отдельно. А этот скрипт, который должен по идее облегчать работу сайта, НЕ ДОЛЖЕН проедать борозды на жёстком диске при каждом обращении. Если уж искать файл, то точечно, по совпадению айпи. А иначе, вместо ожидаемого во влажных мечтах уменьшения нагрузки, в один прекрасный день сервер встанет колом. То же самое касается и остальных циклов, нагрузка копеечная но все равно, на пустом месте менять O(1) на O(n) не стоит.


Дальше. Вот это вот скараментальное


die('Директория кэширования активных пользователей не создана или закрыта для записи.');

— вот кому, КОМУ мы это пишем? Атакующим злодеям? Чтобы они надорвали животики, если случайно увидят этот лепет своих логах? Нет? А кому тогда?
Не пора ли уже понять наконец, что боевой сайт — это не домашний компик, за которым ты и программист, и единственный пользователь. И все эти die как минимум совершенно бессмысленные, а как максимум — несут конкретный вред, сообщая нехорошим людям информацию о внутреннем устройстве системы.
Надо потихоньку открыть для себя, что ВСЕ системные ошибки на боевом сайте пишутся только в лог, и никогда не выводятся клиенту.


Сами по себе эти проверки бессмысленные и вредные. Никогда не нужно подменять подробное, адекватное, содержащее тонну отладочной информации системное сообщение об ошибке на невнятный пересказ. Если выкинуть эти бессмысленные проверки, то РНР подробно напишет — ПОЧЕМУ он не смог открыть файл, и КАКОЙ ИМЕННО.


str_replace('\\' — зачем здесь этот карго-культ? В чем смысл этих глубокомысленных телодвижений? Зачем что-то заменять в полученном от операционной системы имени файла? Чем исходный путь не устраивает?


Мне кажется, если бы Хабр сделал сервис для code review, то можно было бы канализировать энергию джунов в совершенно другое русло. Было бы и больше постов, было бы больше отзывов, было бы больше пользы и было бы гораздо меньше негатива от тех, кто пришел почитать на Хабр адекватные материалы, а не первые пробы робкого пера.

Спасибо коллега! Впечатлило, единственный стОящий комментарий на мою статью.

Чуть поясню, этому коду уже лет 5-6, но работает. Применял я его редко, но и по сей день фильтрует от "свидетелей вордпресс", а чаще просто стопорит частые запросы страниц.

В полной версии кода: ежесуточно скачивает базу ip (cidr) российскую, делает её бэкап на случай, если в следующие сутки не скачается новая, и проверяет адрес по диапазону, если не подошёл, блок. Прошу, ничего не говорить и об этой фишке, сам знаю :-) Но, по факту, на нескольких малонагруженных проектах это работает и периодическая проверка логов на шареде только подтверждает паломничество "свидетелей вордпресс".

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

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

Мне очень нравится ваш оптимизм, но настораживает, что вас не тошнит от своего же кода шестилетней давности. Любого нормального разработчика должно. Это очень, очень плохой признак.


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


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


На случай если вы неверно меня поняли — на Хабре пока нет сервиса для code review, и выкладывать статьи для этих целей — гарантированно получить минусов полную панамку.

Ещё раз благодарю за адекватную оценку. Хотя оптимизма здесь нет, я реалист. А что касается тошноты кода, то здесь как то равнодушно отношусь к этому. Код для "школьника", соблюдены все каноны (табы с комментами).

Скрипт забавы ради, но работает же. Вчера словил некоторый траффик отсюда, всем спасибо, краш-тест пройден :-)

Скрипт собственно и задумывался, чтобы отсечь "свидетелей вордпресс", а не фильтрации ip и стран (это я в рабочем проекте докрутил этот код).

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

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

Поддержу автора, мне очень понравилось решение, и сам код легко читаем для новичков, красиво - правильно оформлен.

веб сервер с уже установленным языком сценариев вполне самодостаточный для какой-то защиты, поэтому fail2ban считаю избыточным, лишним, и это прекрасный пример в статье. а вот как блокировать, что выдавать, будете ли вы просто писать в файлики, или sqlite, или может быть "error_page 301 400 403 404 500 502 503 504 =444" и т.п. это на усмотрение автора, но файлики мне тоже очень нравятся, наглядно и просто.

НЕ ДОЛЖЕН проедать борозды на жёстком диске при каждом обращении

Если стоит выбор между удобством, наглядностью, простотой и при этом вы используете 1% ресурсов предоставляемого хостинга, то нет смысла усложнять работу, чтобы снизить нагрузку до 0.5%. Т.к. плата за борозды уже включена в ежемесячные платежи. Хороший пример - популярность докер контейнеров.

Вам тоже задам вопрос, какое решение? Решение какой именно задачи?


Чушь про "выбор между наглядностью" даже комментировать не буду.

 красиво - правильно оформлен.

Нет

Лучше отдавать 502ю ) Бот подумает что вы лягли и перестанить ddos )

нет, лучше отдать 503, так как можно указать retry after

418-ю, бот подумает, что это чайник и перестанет ddos!

нет, не перестанет. это из моего 10-ти летнего опыта практических занятий по этой теме)))

можно «пощупать» уровень интеллектуальности бота-дятла, отправив ему 301/302/308 с указанием локейшена на 10 или 100 гигабайтный файл (есть такие, для проверки скорости интернета) где нибудь в голландии или колумбии.
Если захлебнется через час, значит ботовладелец исчерпал место у себя на VPS.
Но так делать не надо, это нехорошо, не надо быть редиской!!! Это чисто для анализа ботов способ.

а zip\gzip-бомбы не актуальны?

так делать не надо, это нехорошо, не надо быть редиской!!!
add_header X-Warn-Bots BotsWillBeKilled always;
Вроде как предупредили ботов, а то, что они не читают этот заголовок — «С моей стороны пули вылетели. Проблемы у вас».

Нет, конечно.

Бот же не будет распаковывать архив, он его просто скачает.

Архивы тут не при чем, речь про сжатие НТТР трафика.

А если ещё подвесить на отдачу такого gzip-нутого http потока ограничение скорости в 10-20Кбит/с, то становится весело (пока не понимаешь, что у тебя на сайте висит 5000 ботов и жрут ресурсы кол-ва соединений).

Один из базовых способов обхода защиты, указать в user agent, что ты бот гугла или яндекс. Хотя раньше такое срабатывало, сейчас редко, банят по диапазону ip

Часть запросов поисковые боты делают без указания своего UA, именно по причине выявления случаев, когда сервер отдает разный контент для бота и для живого посетителя.

Поэтому, пока еще ваш проект не потерял позиции в гугле/яндексе, изучите nslookup, чтобы более достоверно определять apple/google/yandex/msn/petalsearch/mailru поисковых ботов.

После этой реализации, вы получите моральное право записать в черный список тот айпи, у которого UA прикидывается поисковым ботом, но не является им по сути.
UFO just landed and posted this here

Получился велосипед, который довольно медленно работает (хотя и быстрее, чем неповоротливый Битрикс).

Обойти его довольно несложно, например, насколько я понимаю, отдать в запросе "127.0.0.1" в качестве REMOTE_ADDR не проблема, если вам не нужно получать ответ сервера. Или просто прикинуться ботом.

В целом код такой тоскливо-ностальгический, все когда-то (лет 10 назад) писали что подобное, наверное. Может даже с echo в каждой строчке. Но вряд ли кто-то этим гордился и выкладывал.

Сейчас вместо таких велосипедов есть github и соответствующий топик на нём, там много разных интересных решений. Почитайте, как это решается, это намного полезнее код-ревью данного велосипеда.

Я бы не сказал что "отдать в запросе 127.0.0.1 в качестве REMOTE_ADDR" это "не проблема". Хотел бы я посмотреть на того героя, который возьмётся провернуть этот фокус. Думаю, вы перепутали REMOTE_ADDR с одним из НТТР заголовков. В которые действительно можно насовать чего угодно, и обойти эту "защиту" как два пальца.

Мне кажется, что на уровне TCP это всё же можно подменить, просто ответ тогда не получишь. Но, может, вы и правы, проверить быстро не могу.

Другое дело, что в данном скрипте достаточно подменить HTTP_X_FORWARDED_FOR, чтобы функция вернула его в getIp() - хоть 0.0.0.0.

Подменить можно, но дальше компьютера пакет с адресом 127.0.0.1 не уйдет. Всё дело в нём.
Какой угодно другой — пожалуйста. Если подменить на уровне TCP исходящий адрес на любой публичный IP, то вот тогда все так и будет как вы написали — запрос дойдет, адрес будет поддельный, но ответа не получишь.

Интересно, спасибо.

Я из-за тебя на стройку пошёл (((

Спасибо за поддержание репутации PHP на соответствующем PHP уровне. А то меня facebook с их hiphop начал смущать. Вижу, PHP, написан как PHP, работает как PHP.

Короче, был лет так 10 назад в дорвеях такой генератор, кажется sed назывался. Он парсил выдачу поисковиков и на этом контента формировал страницы. Ну так вот там был забавный баг, который видимо есть и в этом коде.

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

Ну так при кэшах более 25000 файлов, убивался сервер. Так как каждый раз при создании новой страницы, запускалась процедура очистки кэша. А opendir на такой объем работает нп мгновенно. Тогда ещё и ssd не было.

Если в секунду создаётся хотя бы 2-3 страницы, сервер падал. Исправлялось это все ограничением запуска этой процедуры, раз в 15 минут.

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

Представьте, 2 минуты нагрузка 5000 уникальных ip, создаётся 5000 файлов. При повторном обращении, скрипт должен пробежать по всем 5000 файлам, чтобы найти нужный и убрать просроченные.

Ну то есть 5000 обращений хотя бы по 2 раза, за 2 мин, потребуют 5000*5000 чтений файла. Есть вероятность что сам скрипт прикончит сервер а не сама нагрузка.

Я конечно не эксперт по php, но предположу что нужно функцию проверки разбить хотя бы на две:

Очистка кэша и Проверка ip хороший или плохой.

Мне не нравится формат хранения ip, с датой на конце, не проще ли хранить эту информацию в файле?

Проверка была бы такой (обычно в кэши я люблю делать md5 от строки, чтобы не бороться со спец.символами и хацкерами):

If (is_file(md5($request_ip))) {

Прочитать данные и вернуть True или false

} else{

Сохранить данные

}

Предполагаю что такая проверка будет работать на порядок шустрее opendir. И может спокойно выдержать и 5000 и 10000 запросов.

И отдельно раз в 1 минуту очистка данных.

Кроме этого, есть нюанс по поводу того, что если допустим бот будет обращаться к сайту в 1 секунду, 59 секунду, а потом в 61,62,63 секунду, то он должен быть забанен, так как в интервале между 59 и 63 секунде было 4 обращения, но этого скорее всего не случится. Но это уже нюансы. Так как это усложенние скрипта и хранения интервалов.

А так по хорошему, хэш от ip+browser, в файл писать построчно интервалы обращений, а при проверке проверять за последних 60 сёк, сколько было обращений.

ЗЫ. Ни на что не претендую, просто взгляд со стороны.

Да любой sql решение включая даже sqlite будет надёжнее чем это на файлах.

Данное решение надо показывать - как не надо делать.

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

Вообще-то, строго говоря, БД здесь тоже не совсем при делах. А вот для кого это просто идеальная задача — так это для Редиса. Персистентность нафиг не нужна (даже если хоть вся база побьётся — да без проблем!), а скорость работы на порядок, а то и порядки выше. И без типичных для БД блокировок и тормозов при частых записях. Плюс автоматическая чистка мусора, которая чуть ли одна не перевешивает все остальные достоинства. В общем со всех сторон идеальное решение.

Тогда уж System-V, ещё более шустрая штука, нежели редис. Да и доступна почти что "из коробки", не?

Слушай, уот из систем-ви? Первый результат в гугле это версия юникса, с добавлением слова кэш перекидывает в процессоры.


Да я и не уверен, что здесь нужно больше скорости. Мне до сих пор не приходилось упираться производительность редиса.

Ну я имел ввиду System V IPC. Это *nix АПИ для прямого доступа к оперативной памяти, доступной для любых процессов (в рамках прав юзера, создающего эту область памяти).


Если говорить о коде, то в похапэ будет из коробки работать вот такой код:


$memoryId = 42;
$memorySize = 1024 * 10;

$memory = shm_attach(ftok(__FILE__, chr($memoryId)), $memorySize);

shm_put_var($memory, 1, XXXX);
shm_put_var($memory, 2, YYYY);

shm_get_var($memory, 1); // Эта переменная будет доступна любому пхп процессу

Ессесно есть и минусы.
1) Например эти самые переменные сериализуются, что будет медленнее, нежели даже прямой доступ через FFI или ext-shmop.


пыщ
\Benchmark\Memory\ConnectBench

benchSystemV............................I199 - Mo1.938μs (±15.99%)
benchShmop..............................I199 - Mo1.285μs (±24.52%)
benchFFI................................I199 - Mo1.811μs (±26.10%)
benchFFINoValidation....................I199 - Mo1.453μs (±21.05%)

2) А ещё придётся научиться юзать мьютексы для синхронизации данных в памяти.
3) А ещё это онли линупс. Если нужно кроссплатформенное решение, то придётся юзать ext-shmop, ext-sync или ext-ffi (под виндой они юзают ессесно не system-v, а всякое MapViewOfFile из memoryapi, которое почти тоже самое).

Можно я не буду это комментировать? :)

Только меня одного смущает, что часть кода не видно без танцев с бубнами через f12.

По поводу проверки ботов по user agent, такое себе решение, на моих сайтах 90% ботов имеющих гео локацию с китая и прочих стран, в которых никогда не было серверов гугла и яндекса, обладают строкой user agent яндекс и гугл ботов. Более того, с одного ip приходят как гугл так и яндекс боты ))). Так что без определения и проверки гео локации и подсетей поисковых ботов, эффективность решения очень слабое...

Есть вопросы по скрипту. Основной - есть ли в нем практический смысл?)

>"мусорные" запросы, раздувающие лог и дающие лишнюю нагрузку на хостинге.

в access.log как сыпало, так и продолжит сыпать. Вместо 200 будет 502. Код 429 (rate limiting) подошел бы лучше. 502 выглядит как проблемы на сервере.

Что будет при нагрузке надо проверять. При распределенной атаке эта проверка, вполне возможно, будет работать в "минус".

  1. Если бот подставит User-Agent известного поискового бота - он не будет заблокирован. Это уже сводит все усилия на "нет". Мелочь, но в примере в коде в массиве $options 47й элемент пустая строка '', то есть в любом случае is_bot() вернет true.

  2. Ложные срабатывания, если, например, группа студентов за одним IP. Как-то некрасиво показывать "Вы заблокированы" настоящим пользователям. В худшем случае считаю, надо показывать капчу, при прохождении которой лимиты резко возрастают.

  3. Множество обращений к FS, что плохо влияет на перфоманс, поэтому снова вопрос целесообразности. При каждом реквесте на PHP читать/писать в FS файлики с IPs... "Банить" по стране стОит уровнем выше, как и по IP в целом, чтобы данные тянулись с shared памяти. Nginx rate limiting (не пробовал), CloudFlare умеет - да, это уже не про shared, а на shared не вижу смысла обмазываться такими скриптами, т.к. все еще не понятны плюсы при наличии минусов.

Sign up to leave a comment.

Articles