Вот уже скоро будет год, как я начал заниматься вебдевелопингом. Скажу сразу, что веб не является моей основной профессией — я по прежнему делфи-программист. А веб — это как часть моей широкопрофильности :)
За год довольно много чему научился, приобрел опыт. Чем и хочу поделиться.
Спам.
Многие решают стандартным способом — обязывают пользователя вводить капчу. Способ надежный и проверенный, но, тем не менее, не лишенный недостатков: во-первых, лишний напряг честному пользователю, а во-вторых, это надо еще специальные скрипты ставить (ну я до сих пор не знаю, как это реализовано, потому для меня это пока сложно :).
Тем не менее, со спамом можно бороться и без капчи. Способ очень простой и довольно известный: на форме есть скрытое поле, назовем его ver-code, заполненное заранее известным значением. Значение меняется раз в день/неделю/месяц. При постинге скрипт проверяет это значение и если оно не совпадает, посылает спам-бота куда подальше. Суть метода заключается в том, что спаммеры не успевают обновлять свои базы и постят, используя старый ver-code либо вовсе без него. Конечно, это не спасает от более умных ботов, которые каждый раз загружают страницу, но поверьте, спам сократится в разы — проверенно на собственном опыте. Также есть очень малая вероятность, что за бота примут добропорядочного пользователя: в этом случае матюганы в сторону бота меняем на вежливую просьбу перезагрузить(Refresh) страницу и повторить попытку — боту то все-равно, а вот пользователь поймет вас правильно :)
Также есть вполне рабочий способ, не использующий капчу, и в то же время использующий ее. Все банально: вместо капчи вешаем статическую картинку. Все. Чтоб боты прошли такую тривиальную защиту нужно, чтоб кто-то постарался. А именно увидел, что капча не меняется, оторвал свою пятую точку, и подкрутил настройки спаммерского ПО. Но кто это будет делать для сайта vasia.pupkin.org? Сей метод уже более полугода работает для сайта, и никого спама я не видел (точнее видел в логах, подробнее тут). Хех, интересно то, что несколько клиентов сообщали о "заклинившей" капче :)
Безопасность
Первое правило: никогда не доверяй клиентской стороне. Это учат в школе. Этим прожужжали все уши. И тем не менее многие вебдевелоперы допускают ошибки.
Думаете что если вы владелец http://vasia.pupkin.org то его никто не будет ломать? А вот и ошибаетесь. Не хакер, так бэд-бот: будьте готовы, что ваш сайт начнут пробовать на прочность несколько десятков раз в день. Бэд-боты как любые другие краулеры гуляют по сети и пробуют сайты на уязвимости: будь то известные дыры в различных CMS или стандартный набор SQL-injection — вся информация о найденных брешах отправляется создателю бота, а он уже придумает, что с вами делать.
Думаете, что если у вас все входящие данные экранируются, то SQL-injection не страшен? А про то, что в SQL'е все это нужно обернуть в апострофы не забыли? Я на вот этом и попался. Модифицированный пример из википедии:
$id = mysql_real_escape_string($_REQUEST['id']);
$res = mysql_query("SELECT * FROM news WHERE id_news = $id");
Вроде экранирование есть, но дыра так и осталась не прикрытой: если в id передать "-1 OR 1=1" то вместо новости с заданным идентификатором будут выбраны все имеющиеся в базе новости.
Хорошо, что сайт сделан вручную, без никаких CMS — ошибка не стала уязвимостью, и никак себя не проявляла. Вообще хорошее правило вместо универсального "SELECT * FROM Table" выбирать только то, что требуется в данный момент: "SELECT field1, field2 FROM Table".
А еще хорошим правилом является просмотр логов, благодаря коим и была выявлена эта ошибка. Вообще логирование — очень важная штука. Думаю, это все знают и понимают: будь то ругательства MySQL-ля, ерроры в скриптах, или что-то еще — все нужно логировать. Но также будет очень полезным записывать и все "подозрительные" запросы, смахивающие на попытки взлома системы: кроме того, что можно всегда быть в курсе ее состояния (или хотя бы знать, что же с ней произошло :), так еще и параноидальный админ (прям как я:) сможет вовремя увидеть и быстренько подлатать брешь или сомнительный участок. А такие участки были мною исправлены.... "Подозрительность" определяется просто: например, если там где должно быть целочисленное поле идет что-то левое. В таком случае ругаемся пользователю и тихонечко пишем в лог. Такая штука полезна и для определения "а была ли попытка взлома?" — всегда можно посмотреть access-логи и восстановить полную картину: вполне возможно, что не все записалось и часть действий хакера осталась незамечена (и никак не обработана/заблокирована!).
Ни в коем случае нельзя показывать пользователю интимные подробности произошедшей ошибки — это то и хакерам нужно. Казалось бы все и так знают, и у всех так сделано. Не у всех. В нете полно сайтов дающих интим, если умело попросить :). Приведу пример не так давно обнаруженных мною уязвимостей на ряде сайтов. Скажите, вы всегда проверяете валидность загружаемых файлов? А когда работаете с загруженным контентом придерживаетесь правил защиты от SQL-injection? А вот почти каждый десятый даунлоад-архив (всего таких больше сотни) валится при попытке засабмитить PAD-файл (XML-файл с описанием продукта) в нужном поле которого оказалась одинарная кавычка. Причем большинство из них как раз выдают пользователю те самые интимные подробности формата таблицы БД, куда все это дело не удалось добавить.
PHP-Apache
Эта связка глючная. Причем безнадежно. В одной версии фиксят баг — он появляется в следующей, причем приводит с собой еще семеро.
Нельзя быть уверенным, что скрипты прекрасно работающие в одной верcии, успешно заведутся на следующей. Взять, например server-side includes. Я нашел три баг-репорта для разных версий (!!!) и везде они были пофиксены и везде предлагали скачать свежий CVS-снапшот. Хотя у меня была версия, для которой "якобы" этот баг был исправлен, но, увы, можно было отправлять и четвертый баг-репорт... Та же история и с оверрайдом 404-го статус-кода на обработчике ErrorDocument: в одной версии работает, в более поздней — нет, причем баг-фикс идет где-то посередине. Хорошо, когда такой баг проявляется только на одном сайте/скрипте к которому имеешь доступ. Гораздо хуже, когда пользователь не может установить и заставить работать твой "бажный" скрипт (как было с DynamicPAD).
Ни в коем случае нельзя слепо копипастить куски php-кода из тематических форумов и туторных сайтов — себе же дороже будет. Здесь несколько другая ситуация чем с другими ЯП: php — это серверный скрипт, требующий особого подхода к безопасности. А вот обычно те, кто добродушно делятся своим кодом, о безопасности, похоже, и не слышали. Потому и оказывают медвежью услугу.
Ошибки и ворнинги php-интерпретатора в браузере видели все — такое есть на каждом n-ом сайте. И каждый мог судить о некомпетентности программистов написавших тот сайт или скрипт. А вы тоже хотите афишировать свою безграмотность? Чтоб вас также само судили? Нет? Тогда нечего выводить интимные подробности тому, кому они не предназначены:
error_reporting('E_NONE');
В то же время показываем их только тому, кому нужно (ни в коем случае не глушите все ошибки "ухом" - @. Это плохо кончится):
- в php.ini:
log_errors = on
error_log = /var/logs/php/errlog.txt
- в .htaccess
php_flag log_errors on
php_value error_log /var/logs/php/errlog.txt
- в коде php-скрипта
log_errors("on");
error_log("/var/logs/php/errlog.txt");
Ну и пару слов про почту.
Никогда не следует надеяться на функцию mail — письмо может так и не дойти до адресата, и вы никогда об этом не узнаете. И не надо говорить, что ваш sendmail работает безупречно — дело может быть вовсе не в нем: мало ли чего может приключиться с письмом по пути к точке назначения. Так что логируйте все тексты писем, которые вы отправляете — если даже посылка и не дойдет куда нужно, то она, по крайней мере, не пропадет безвозвратно. И, быть может, вы не потеряете клиента.
SQL-запросы экранируете? Будьте добры экранировать передаваемые в mail хидера (обычно это From, Reply-To, Subject). Иначе не удивляйтесь, что ваш мейл-сервер занесли в черный список как злобного спаммера. Достаточно просто "резать" все переносы строк в этих полях (они обязаны быть однострочными).
На последок. Как говорил вождь, учится, учится, и никогда не расслабляться. Помните: выживут только параноики :)