[web-Devil]
Вт, 17.12.2024, 02.46.44
» Меню сайта
» Категории раздела
PHP [18]
Уроки PHP
MySql [6]
Все о MySql
» Статистика
Главная » Статьи » Програмирование » PHP

Урок № 14 - Безопасное программирование.



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

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

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



О том, как надо



Ну, со вступлением вроде бы разобрались, перейдем к делу. С чем же работает каждая программа? Конечно же, с данными. Данные принимают, данные передают, данные обрабатывают, их ищут и так далее. И вот на каждом этапе нужно думать о безопасности. Да, так оно и есть. Нельзя сначала написать скрипт кое-как, а потом приступать к фазе его "дезинфекции". Так не выйдет - мы все люди, и что-нибудь точно забудем. Да и потом, если сразу все делать правильно, то не возникнет и сомнений потом. А, значит, и нужды перепроверять. Хотя, конечно, программ без ошибок не бывает. Но в наших силах сделать так, чтобы их число было минимальным.





О пользователях и хакерах




Теперь я бы хотел рассказать о том, зачем же делать безопасным нашу программу. Ведь если пользователи заинтересованы в сохранности своих данных, с чего бы им вредить системе?.. Так вот, далеко не все пользователи заинтересованы в сохранности данных. А точнее - есть такие, которые заинтересованы в не сохранности чужих данных. Опять же - номера кредитной карты. Как ведь хочется его украсть. А значит, если у нас есть такие деятели, то я настаиваю: с точки зрения системы любой пользователь === хакер. То есть, подводя итог абзацу, скажу: в отношении всех действий пользователя действует презумпция виновности.





Мишени и лазейки



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

Пример. У нас есть скрипт авторизации - самый частый случай. Пусть он выглядит так:


<?PHP
$admin
=0;
//тут может быть еще что-нибудь предварительное
$admin=$_REQUEST['admin'];
if(
$admin)
{
   
//..функционал админа
}
else
{
   
//что-то еще
}

?>


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


CODE:

script.php?admin=1

То кто угодно увидит часть администратора. Ведь $admin придет из запроса к скрипту и будет предустановлено. Это - классическая ошибка "register_globals = On" + "неинициализированные переменные". В самом деле, ведь мы не инициализировали переменную $admin, вот и результат на лицо.

Самым правильным решением будет отключение register_globals и явная инициализация всех используемых в скрипте переменных.



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


<?PHP
$rgResult
=array();
$processName=$_POST['processName'];
exec("ps aux | grep ".$processName$rgResult);
foreach(
$rgResult as $value)
{
   echo(
$value."<br>\n");
}

?>


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

В том самом месте, в котором мы просто так передаем имя процесса. Ведь мы же можем в $processName написать, скажем:


CODE:

php && cat /etc/passwd

Это выполнит сначала поиск информации о выполняющихся php-скриптах (в шелле) - скорее всего, ожидаемый ввод, а вот затем выполнит вывод информации системного файла - не слабо выходит. Единственная поправка - современные UNIX - системы (как Linux, FreeBSD к примеру) довольно устойчивы даже на случай таких "кривых" скриптов. Скорее всего, прочитать содержимое этого файла скрипту попросту не даст сама ОС. Но не стоит надеяться на систему, нужно предотвращать такие попытки на уровне скрипта. В данном случае - как? Просто задать список разрешенных для просмотра процессов:


<?PHP
$rgAllowedProcess
=array("smbd""nmbd""httpd");
$rgResult=array();
$processName=$_POST['processName'];
if(
in_array($processName$rgAllowedProcess))
{
   
exec("ps aux | grep ".$processName$rgResult);
   foreach(
$rgResult as $value)
   {
      echo(
$value."<br>\n");
   }
}
?>


И все тут. На пользовательской стороне можно предусмотреть, скажем, выпадающий список с именами разрешенных процессов.



Приведу также третий распространенный пример небезопасного кода. Опять же, пусть у нас есть скрипт аутентификации:


<?PHP
$login
=$_POST['login'];
$password=$_POST['password'];
//предполагаем соединение с БД установленным
$result=mysql_query("SELECT user_id FROM users WHERE login=$login AND password=$password");
if(
mysql_num_rows($result))
{
   
//все хорошо - пользователь найден, выполняем процедуру его логина
}
else
{
   
//какая-то ошибка для пользователя
}
?>


Это классический пример так называемого SQL-Injection. Точнее. не его самого, а возможности для него. Ведь представим себе, что передадим в поле $password вот что:


CODE:

12345; UPDATE users SET password='0' WHERE login='admin'

Что выйдет? Все верно, MySQL получит запрос (соединение-то уже установлено) и выполнит запрос на обновление пароля пользователя admin. После этого заходим этим пользователем с паролем '0' и можно считать задачу выполненной.

Для защиты необходимо экранировать пользовательский ввод. Это значит, что все специальные символы предваряются специальным символом "\" или заменяются. Для этого существуют функции:

mysql-real-escape-string

Для библиотеки собственно mysql; mysqli-real-escape-string для билиотеки mysql; и
addslashes для общего случая.



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





Оборона тыла



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

Опять же, пример:

У нас есть 2 файла:


/www
    |
    +---database.inc
    |
    +---script.php


И script.php, скажем, выглядит так:


<?PHP
include("database.inc");
//далее работа с БД

?>


Собственно, database.inc нужен для соединения с БД. Казалось бы - все хорошо и удобно, не нужно по нескольку раз в скриптах писать строки соединения с БД. Но опять же хитроуный пользователь вводит в строку http://наш_сайт/database.inc

И что же? Да ничего хорошего. Пользователю просто отобразится этот файл, и все. Просто потому, что веб-сервер не знает такого типа файлов (в большинстве случаев) и предлагает его скачать. Ну а зная пользователя и пароль к БД можно много чего сделать.



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

Иногда советуют использовать .htaccess файлы для запрещения доступа к таким файлам. Но я уверен - зачем так делать, если у нас есть универсальное решение? Решение с .htaccess я бы назвал скорее следствием, решением надуманной проблемы. Сильно сомневаюсь, что без всяких там хитрых *.inc не обойтись.



Далее - пример для БД. Здесь чаще всего проблемы с безопасностью возникают, когда у пользователя БД, от имени которого работает скрипт, слишком много прав. Правило номер 1 - никогда не работайте в скрипте от имени БД-пользователя root. Не нужно так делать, и все тут. Этот пользователь не предназначен для работы из скрипта. Исключения - слишком редки, чтобы так не делать.



В остальном я бы рекомендовал под каждый проект создавать свою БД, для этой БД - одноименного пользователя и выдавать этому пользователю полные права (но без права GRANT) на эту базу. Здесь могут быть исключения, когда с одной БД должны работать несколько пользователей.



Тогда права следует раздавать так - сначала отобрать все права, а затем по мере необходимости выдаввать. Тогда набор прав будет строго минимален. Затем добавлю, что все пользователи должны иметь право только локального логина (инача говоря, пользователи с полем host, равным "%" в служебной таблице, по возможности, должны отсутствовать). Если уж и есть необходимость удаленного логина, то лучше каждый хост добавлять отдельно, избегая пресловутого хоста "%"



Теперь немаловажная составляющая - сама система. Имеется ввиду операционная система. Я уже упомянул, что UNIX-системы очень устойчивы, когда речь идет о безопасности. Но если не думать, то можно наломать дров и в таких системах. Правила я бы сформулировал так:

- Для каждого сервиса (веб-сервер, сервер БД, всякие фронт-енды, ускорители и т.п.) создаем отдельного пользователя, группа у всех одна (например, daemon). Право на исполнение дается только для тех файлов, которые фактически должны выполняться (а не просто chmod -R 755). Права "7" - полные права, стоит выдавать только на те каталоги/файлы, которые не могут иметь других разрешений. Как пример - каталог, куда мы принимаем файлы от пользователей (хотя сам по себе такой каталог - потенциальная брешь, подумайте почему).

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

- Логировать самими скриптами все необычные действия пользователей. Иначе говоря, если все делалось правильно, и была отловлена попытка (не важно, случайная или злонамеренная) взлома, администратор должен быть уведомлен. Желательно так, чтобы пользователю ничего не отображалось при этом.

- Все php-сообщения об ошибках должны быть отключены. Ведь зная ошибки, хакеру по ним можно узнать структуру системы. А это облегчает задачу взлома. Тестировать систему, правда, я настоятельно рекомендую со всеми включенными ошибками. Идеальная ситуация - программа доведена до состояния, когда даже при всех включенных ошибках она не выводит даже Notice в любых случаях. Но даже в этом случае нужно отключать вывод ошибок, когда программа предоставляется пользователям.



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

Категория: PHP | Добавил: web-Devil (20.11.2009)
Просмотров: 1063 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
» Поиск
» Друзья
  • В Контакте
  • Deposit Files (регистрация)
  • $$$ для web-мастеров
  • » Реклама
    Copyright [web-Devil] © 2024Хостинг от uCoz