Реальный пиарСоздание сайтовБезопасность → PHP профессионально... Безопасность

PHP профессионально... Безопасность

скрипты для сайта

Привет всем web-программерам :) Вот наконец у меня дошли руки до Блокнота :o), в котором я и пишу сейчас эту статью. Статья, имхо, чрезвычайно важной тематики, что ясно по названию - "Безопасность в PHP". Именно: я постараюсь описать наиболее распространенные приемы защиты php-скриптов от злых хакИров. Имейте в виду, эта статья - не панацея от взлома. Просто применение этих приёмов несколько усложнит задачу взломщика. Настоятельно рекомендую всем использовать свои методы защиты, написанные с учетом специфики именно вашего сайта. Если хакер не сможет догадаться, как все "закручено" в вашем скрипте, и какие там стоят "заглушки", то желание ломать у него, скорее всего, быстро пропадет. Что нам и надо :) Итак, disclaimer окончен, перейдем непосредственно к безопасности.
Не секрет, что 99% (а то и все 100) всех взломов веб-приложений происходят в результате того, что хакер передает скрипту не те данные, которые тот ожидает получить. (Простейший пример - гостевая книга, где можно писать HTML-тегами. При написании скрипта неопытный программер даже не подумал о том, что пользователь может передать скрипту что-то еще, кроме plain text-a). Поэтому, если ты думаешь, что кто-то может попробовать пощупать твои скрипты на безопасность, встрой в скрипт проверку на соответствие получаемой инфы твоему типу данных. За примером далеко ходить не надо: имеется гостевая книга, сообщения которой выводятся не на одной странице, а разбиты на несколько. При этом, чтобы прочитать, скажем, четвертую страницу, вызывается скрипт view.php?page=4. Где переменная $page принимает целые значения. Целые? Ок, так и не позволим хакеру дать ей, значение, например, "?>": $page=intval($page) вернет целую часть действительной переменной, 0 - для строковой переменной, и $page, если $page - целая переменная. Теперь в скрипте можно написать: if($page==0) echo("Похакай мне тут!"); и хакер обломается :)
Теперь еще один важный момент. (Если вы еще не забыли, я по-прежнему рассказываю о PHP без MySQL, т.е. в моих примерах мы будем работать с текстовыми файлами). Допустим, мы имеем скрипт-шаблонизатор main.php, который будет вызываться с параметром page=abc (main.php?page=news, к примеру), и при запуске будет пытаться прочитать содержимое файла "text/abc/text.txt", дабы вставить его в страницу и показать пользователю. Теперь представим, что каталога "text/abc" не существует (хакер опять-таки задал неверное значение), что вернет нам пхп? Правильно, ужасные, нарушающие весь дизайн сайта строки "Warning: fopen("text/abc/text.txt","r") - No such file or directory in /home/user/main.php on line 20, Warning: Supplied argument is not a valid File-Handle resource in /home/user/main.php on line 21). Конечно, никаких особо вредных последствий для сайта при этом не будет, но... А что, если в нашем файле скрипт не читает инфу из файла, а пишет туда? Может получиться нехорошо :) К примеру, если хакер вызовет скрипт так: main.php?page=../, скрипт может занести инфу в совсем уж непотребное место :) Итак, как избежать такого эффекта? Посмотрим. Во-первых, даже если хакеру и удалось спровоцировать ошибку, он не должен знать о своем успехе. Для этого заменим строку $textfile=fopen("text/$page/text.txt", r); на следующую: $textfile=@fopen("text/$page/text.txt", r). Как видите, добавилась собака (@). Для чего это нужно? Очень просто - символ @ блокирует вывод всех сообщений парсера об ошибках, связанных с той функцией, перед которой стоит собака. Так что, даже если ошибка и произошла, хакер об этом не узнает. А теперь - как предотвратить такую ошибку. Это очень просто - перед чтением файла следует сделать проверку на его существование. Примерно вот так:
if(file_exists("text/$page/text.txt"))
$ok=1;
else
$ok=0;

if($ok!=1) {
echo("hacker? wow...");
exit;
}

как видишь, все просто :)
Так, с заменой параметров прямо в строке запроса разобрались. Взломщик потерпел полное фиаско и решил поисследовать твои формочки. И тут мы его обломим :) Предположим, что хакер решил поправить некоторые параметры, к примеру, формы гостевой книги, и посмотреть, что получится. Для этого ему надо сохранить HTML-файл с формой к себе на винт и отредактировать в блокноте, после чего отправить инфу нам. Отловить такого плохого мальчика проще простого :) Делается это через переменную HTTP_REFERER. Вот простенький код:
$ref=getenv("HTTP_REFERER");
if(!ereg("^http://адрес.нашего.сайта",$ref)) {
echo("error wrong referer!");
exit;

}

Добавь этот код в начало своей гостевухи, и юные хакИры будут несколько озадачены. 90% за то, что на этом месте они перестанут ломать твой код. Для остальной же, более продвинутой публики стоит сделать еще несколько сюрпризов. Как, например, запретить употребление HTML-тегов (только представь, что можно натворить при помощи JavaScript...): я делаю это такой функцией:
function nohtml($string) {
$html = array (
"&" => "&",
""" => """,
"<" => "&lt;",
">" => "&gt;",
"&quot;" => "&quot;"
);
for(reset($html); $key=key($html); next($html)) {
$string = str_replace("$key","$html[$key]",$string);

Эти приёмы усложняют жизнь начинающим хакерам и упрощают тебе - не придется, чертыхаясь, вычищать теги из гостевой / чата / форума.
И последний вопрос, который я хотел сегодня рассмотреть - авторизация. Я чуть со смеху не помер, увидев на одном сайте авторизацию средствами JavaScript. Да-да, не смейтесь! Выскакивала строка запроса, введенное значение прямо в исходнике HTML (!) сравнивалось с верным пассвордом и, в зависимости от результата проверки, происходил редирект броузера либо на error.htm, либо на secured.htm. Автор такой мега-авторизации надеялся, что хакер не успеет после ввода пароля просмотреть исходник HTML, но мы-то знаем, что ВСЮ подноготную client-side приложений можно найти в кеше... Так что единственно надежным (и то не всегда) механизмом авторизации мы будем считать авторизацию со стороны сервера. Как же сделать такую проверку в PHP? Очень просто: в форму вставить объект <input type=password name=password>, а в PHP - код такого вида:
if($password!="qwerty") {
echo("Wrong password!");
exit;
}

Этот способ имеет ряд недостатков. Во-первых, если ты админ, иногда неохота каждый раз вводить длинный пароль. "Подумаешь, есть же кукисы!" - скажешь ты. "Ввел один раз пароль - а дальше он пускает тебя автоматом - эх красота!" Верно, но предположим, что ты используешь прокси. Тогда существует вероятность, что кто-нибудь, сидящий через тот же прокси, запросит твой админовский скрипт, и прокси выдаст ему тот документ, который был сформирован после авторизации! Это нам совсем не нужно. Надо либо делать каждый раз logout, что ведет к тому же геморрою, что и с формами, либо ставить сервак на защищенное соединение (протокол HTTPS ;)). Еще один вариант защиты - положить все админовские скрипты в каталог admin и настроить доступ к нему при помощи .htaccess. Тогда хакеру придется ломать уже веб-сервер, что куда сложнее, чем может показаться. НО доступ к .htaccess есть не всегда. Что же делать? Есть способ проще - RONDO ;) в начало каждого админовского скрипта поместим такой вот код:
if ( ($PHP_AUTH_USER != "admin") ($PHP_AUTH_PW != "coolpassword") ) {
Header("WWW-Authenticate: Basic realm="For admins"");
Header("HTTP/1.0 401 Unauthorized");
echo("<HTML><HEAD><TITLE>В доступе отказано!</TITLE>
</HEAD><BODY><center><font color=red><b>access denied!
</b></font></center><br><br><br></BODY></HTML>");
exit;
}

Итак. Если две переменные $PHP_AUTH_USER и $PHP_AUTH_PW не соответствуют некоторым значениям, формируем окошко с запросом на авторизацию (код 401). Если пользователь ввел правильные логин и пароль, то на время этой сессии он получит доступ ко всем скриптам админа, в которых используется такая авторизация - браузер просто "запомнит" эти значения логина и пароля, и пока ты не закроешь это окно, будет автоматом подставлять их во все запросы. Если ты случайно закрыл окошко, не закончив админить сайт, то окошко выскочит еще раз, что неудобно. Но в IE, например, есть очень удобная галочка Save Password ;) Теперь для того, чтобы авторизоваться, достаточно один раз нажать OK. Удобно нам - неудобно хакИру :) Этот способ практически не имеет недостатков, единственное - он работоспособен не на всех версиях апача. Для того, чтобы все было OK, PHP должен быть установлен как модуль Apache. Ну вот на wallst.ru, к примеру, все работает :)
Надеюсь, теперь тебя не хакнут. Удачи! Если есть какие-то вопросы, пиши в комментах.


Источник: http://www.captcha.ru

Рекомендуем



Кража FTP-паролей Я имею в виду то, что иные программисты, стремясь воплотить некоторые нестандартные идеи, кажущимися им весьма удачными и новаторскими, подрывают безопасность своих систем, открывая щели, форточки и двери для атак


DOS Во-первых, если сайт не оптимизирован, если для каждого посетителя производятся объемные выборки и расчеты, если сайт генерирует страницы секунду или две, даже простого увеличения посетителей вследствие того, что ссылку на сайт опубликовали в каком-то более-менее посещаемом месте, достаточно, чтобы сервер не справится с возросшей нагрузкой


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