#1 Online pharmacy affiliate program! Инвайты в ICQ
 
Feb
03
Posted (Random) on February 03-2007

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




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




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


<input type=text name=title maxlength=20>

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




Далее, не дадим злоумышленнику отправлять данные формы с другого домена. То есть, если он сохранит себе html-код формы отправки комментария себе на локаль, что-то там изменит, и будет выдавать за чистую монету, сервер его обламает и отправит курить бамбук в сторонке. Сделаем мы это вот как:



if(!strstr($_SERVER['HTTP_REFERER'],"http://".$_SERVER['HTTP_HOST']))
{
echo "Произошла ошибка<br>
Форма исполняется лишь на этом домене.";
exit;
}

То есть мы проверяем наличие нашего доменного имени в урле страницы, с которой нам шлют данные. Если его нету, выдаём ошибку.




Теперь, убедившись, что мы получили данные с собственного домена, приступаем к жёсткой обработке и фильтрации этих самых данных. Напишем несколько функций:



//Эта функция проверяет, если в строке есть хотбя бы один символ,
//отличный от: a-z, 0-9, она возвращает пустое значение
function az09($str)
{
if(ereg("^([a-zA-Z0-9]+)$",$str)) return $str;
else return "";
}

//Проверяем E-mail на валидность. В нём может быть сколько угодно
//минусов и подчерков, но должны быть символы "@", ".", он должен весь
//быть из латинских символов, и зона должны состоять из 2-4 симоволов.
function email($str)
{
if(ereg("^[a-zA-Z0-9\._-]+@[a-zA-Z0-9\._-]+\.[a-zA-Z]{2,4}\$",$str))
{
return $str;
}
else return "";
}

//Запрещаются все html-теги, кроме перечисленных
function text($str)
{
return strip_tags($str,"<p><br><b><u><i>");
}

Этими функциями всё сказано. Вешаем нужную нам функцию на нужную переменную и получаем обработанный результат:



$title=az09($_POST['title']);

Если в $_POST['title'] содержались символы, отличные от a-z, 0-9, функция вернёт пустую строку.




Ещё, поскольку мы ограничили поля ввода в html, неплохо бы сделать substr полученным данным, то есть обрезать в строке все лишние символы:



$title=substr(az09($_POST['title']),0,20);




Этого набора функций вполне хватает для безопасной работы с данными из форм и т.д. Конечно, сразу хочется дополнить эти функции. Например, разрешить пользователю использовать минус в заголовке, тогда в функции az09() изменим [a-zA-Z0-9] на [a-zA-Z0-9-].




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



function my_md5($str)
{
$hash=trim($str);
for($i=0; $i<strlen($str); $i++) $hash=md5($i.$hash."my_word");
return $hash;
}

Как видите, расшифровать такую строку будет непросто. Расшифровка по словарю не даст результата. А от тупого перебора никто не застрахован, но он требует много времени и ресурсов.




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




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





Comments:
Comments closed