За последние 24 часа нас посетили 17480 программистов и 1710 роботов. Сейчас ищут 1800 программистов ...

Защита приложений, написанных на PHP

Тема в разделе "PHP для новичков", создана пользователем Psih, 13 окт 2008.

  1. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Хм... А как вообще с этим Null Byte борятся?
    А вообще имя файла я хотел формировать не зависимо от того, какое оно было у пользователя. Просто проверка типа файла нужна, чтобы потом файлу присвоить аналогичный тип. Ну вроде того:
    PHP:
    1. <?php
    2. ... ...
    3. $file_ext = explode(".", $userfilename);
    4. $num_parts = count($file_ext);
    5. switch($file_ext[($num_parts - 1)]) {
    6. case "jpg":
    7.   $ext = "jpg"; break;
    8. case "jpeg":
    9.   $ext = "jpg"; break;
    10. case "gif":
    11.   $ext = "gif"; break;
    12. default:
    13.   echo "Тип загружаемого файла должен быть ..."; break;
    14. }
    15. # Проверяем сколько записано файлов в каталог
    16. # и присваиваем это число переменной $numfiles
    17. $newfilename = "photo-" . ($numfiles + 1) . $ext;
    18. # сохраняем файл с именем $newfilename
    19. ... ...
    20. ?>
    Я так понимаю, что в этом случае если
    то файл всё равно сохранится как photo-xxx.jpg ?
     
  2. obsrv

    obsrv Активный пользователь

    С нами с:
    2 окт 2008
    Сообщения:
    238
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
  3. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Вот, чтобы собрать наконец-то "в кучку" то что прочитал, хочу спросить. Допустим я получаю в массиве $_GET (или $_POST) что-то от пользователя.
    PHP:
    1. <?php
    2. $page_num = $_GET['page'];
    3. $name = $_GET['name'];
    4. $search_word = $_GET['word'];
    5. ?>
    Что необходимо и достаточно сделать с переменными $page_num (д.б. числового типа), $name (д.б. строкового типа) и $search_word (может быть любого типа, смотря что пользователь искать вздумает, вдруг число), чтобы без опаски делать SQL - запросы к базе, в которых будут эти переменные (или одна какая-то)? (ну, например:
    PHP:
    1. <?php
    2. $sql = "SELECT post, post_date, poster_name FROM posts WHERE post LIKE '%" . $search_word . "%'";
    3. ?>
    Какой посоветуете минимальный и достаточный набор функций для обработки трёх вышепредставленных переменных?
     
  4. Mete0

    Mete0 Активный пользователь

    С нами с:
    18 дек 2006
    Сообщения:
    272
    Симпатии:
    0
    Адрес:
    Gatchina
  5. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Mete0
    С числами не всё так просто
    ***
    intval неправильно обработает числа выше 2^31 (~2млрд)
    ***
    intval пропустит отрицательное значение (в случаях с вставкой его в LIMIT и включенными error_reporting) мы получаем уязвимость раскрытия пути

    Так что проверять (кроме isset) пожалуй лучше is_numeric (вместо intval) и ещё и потом на отрицательность

    Со строками аналогично не всё так просто.
    Для начала надо проверить не пустая ли строка пришла, или например не пришли ли только пробелы, опять-же как и было сказано Magic Quotes, короче РНР штука "зверская"


    Вот примерный разврат который реально стоило бы использовать.
    PHP:
    1. <?php
    2. $page_num = 1;
    3. if (isset($_GET['page'])) {
    4.     if (is_numeric($_GET['page'])) {
    5.         if ($_GET['page'] > 0) {
    6.             $page_num = $_GET['page'];
    7.         }
    8.     }
    9. }
    10.  
    11. $name = null; // аналогично и с search_word
    12. if (isset($_GET['name'])) {
    13.     if ('' != trim($_GET['name'])) {
    14.         if (get_magic_quotes_gpc()) {
    15.             $_GET['name'] = stripslashes($_GET['name']);
    16.         }
    17.         // чуть главное не забыл :)
    18.         $name = mysql_real_escape_string($_GET['name']);
    19.     }
    20. }
    21. ?>
    Кстати недавно так-же был прикол, выяснилось что "красивее" использовать array_key_exists('page', $_GET) вместо isset($_GET['page']) но это важно только для извращенцев (типа меня)
     
  6. Mete0

    Mete0 Активный пользователь

    С нами с:
    18 дек 2006
    Сообщения:
    272
    Симпатии:
    0
    Адрес:
    Gatchina
    Про intval.
    На 32-х битной платформе да, в связи с тем что integer в php знаковый (signed), потому и от -2147483648 to 2147483647.
    На 64-х разрядной платформе обрабатывает нормально, ну не суть. Особого смысла проверять на то что число является отрицательным я не вижу.
    Про строки.
    Можно и добавить проверок, я не стал расписывать очевидные вещи, хотя для автора они могут таковыми не являться.
     
  7. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    "не вижу" и "нету" вещи немного разные, поищи как местные админы над интернет магазинами прикалывались, ссылку не даю, лень искать.

    Увы Попов тоже мало чего описал, итоги на лицо :)

    Вопрос всё-же был про
     
  8. Mete0

    Mete0 Активный пользователь

    С нами с:
    18 дек 2006
    Сообщения:
    272
    Симпатии:
    0
    Адрес:
    Gatchina
    Могут понадобится отрицательные значения.

    Более того, он еще любитель конструкций типа do {} while там где им не место, printf'ов и прочей ерунды. Вот только не надо меня к нему приравнивать :)
     
  9. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    По этому я и написал про LIMIT да и рассматриваем мы $page_num (как раз тот случай)

    Не приравниваю, вам до него ещё как до луны пешком :)
     
  10. Mete0

    Mete0 Активный пользователь

    С нами с:
    18 дек 2006
    Сообщения:
    272
    Симпатии:
    0
    Адрес:
    Gatchina
    Да, что-то я оплошал :) Если рассматривать конкретно лимит то конечно отрицательные значения не нужны :)

    Чем дальше от него, тем лучше :)
     
  11. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Спасибо Вам большое!!! Да-да, вопрос был именно про минимальный и достаточный набор функций, я даже жирным выделил это сразу! :) В Вашем ответе хочется увидеть именно всё, что нужно сделать, но чтобы и лишнего не было.
    Просто я вот решил посмотреть, что в phpbb делается с пользовательскими данными перед отправкой sql-запроса. Сперва немного помучался с поиском, потом нашёл, офигел и написал тут свой вопрос. В phpbb (применительно к $username) это выглядело так:
    PHP:
    1. <?php
    2. ... ... ...
    3. $username = isset($HTTP_POST_VARS['username']) ? phpbb_clean_username($HTTP_POST_VARS['username']) : '';
    4. $sql = "SELECT user_id, username, user_password, user_active, user_level, user_login_tries, user_last_login_try FROM " . USERS_TABLE . " WHERE username = '" . str_replace("\\'", "''", $username) . "'";
    5. ... ... ...
    6. function phpbb_clean_username($username)
    7. {
    8.   $username = substr(htmlspecialchars(str_replace("\'", "'", trim($username))), 0, 25);
    9.   $username = phpbb_rtrim($username, "\\");
    10.   $username = str_replace("'", "\'", $username);
    11.   return $username;
    12. }
    13. function phpbb_rtrim($str, $charlist = false)
    14. {
    15.   if ($charlist === false)
    16.   {
    17.     return rtrim($str);
    18.   }
    19.   $php_version = explode('.', PHP_VERSION);
    20.   // php version < 4.1.0
    21.   if ((int) $php_version[0] < 4 || ((int) $php_version[0] == 4 && (int) $php_version[1] < 1))
    22.   {
    23.     while ($str{strlen($str)-1} == $charlist)
    24.     {
    25.       $str = substr($str, 0, strlen($str)-1);
    26.     }
    27.   }
    28.   else
    29.   {
    30.     $str = rtrim($str, $charlist);
    31.   }
    32.   return $str;
    33. }
    Тута :roll: ничего лишнего..? :oops:
     
  12. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Не лучший пример для подражания...

    Короче лучше прочитать http://phpfaq.ru/slashes так как с числами в LIMIT это одни танцы, с обычными цифрами другие, с текстом третьи, а уж с LIKE и вовсе отдельные...
     
  13. Mete0

    Mete0 Активный пользователь

    С нами с:
    18 дек 2006
    Сообщения:
    272
    Симпатии:
    0
    Адрес:
    Gatchina
    Vladson
    Кстати в твоём примере есть "бага".

    Если пользователь сделает вот так: ?name[]=bug, то получим нотис вида: Notice: Array to string conversion.
    Я бы ещё добавил проверку is_array(), например так:
    PHP:
    1. <?
    2. $name = null;
    3. if (isset($_GET['name']))
    4.   if (!is_array($_GET['name']))
    5.      if (trim($_GET['name']) != '')
    6.         $name = mysql_real_escape_string($_GET['name']);
    7. ?>
    А с Magic quotes поступил бы так:
    PHP:
    1. <?
    2.     function stripslashes_deep($value)
    3.     {
    4.         $value = is_array($value) ?
    5.             array_map('stripslashes_deep', $value) :
    6.             stripslashes($value);
    7.         return $value;
    8.     }
    9.     $_POST = array_map('stripslashes_deep', $_POST);
    10.     $_GET = array_map('stripslashes_deep', $_GET);
    11.     $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
    12.     $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
    13. }
    14. ?>
    Где-нибудь в начале...
     
  14. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Лучше не is_array а is_string (нам кроме стрингов ничего не надо, и то что кроме стрингов в гетах могут быть только массивы это справедливо только для тех версий что существуют сейчас, но нет гарантий что это не изменится к 99-й версии)
     
  15. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Собственно, на самом деле в GET в любом случае передается строка, просто строку определенного формата, полученую GET или POST, PHP преобразовывает в массив. Поэтому is_string правильнее.
     
  16. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Спасибо всем за отклики!!! Вот хочу ещё поинтересоваться. Тут недавно говорили про так называемый null-byte.
    Если честно, я толком так и не понял, что это вообще и как хакер может вставить его в запрос, но сейчас не об этом. Приведённого выше Вашего примера достаточно, чтобы обезопасить свой скрипт и от этого null-byte? Функция mysql_real_escape_string() его умеет обрабатывать правильно?

    Не подкините (кто знает) статейку, где рассказывается про null-byte достаточно просто и подробно?
     
  17. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    1 - обычный символ, просто которого нет на клавиатуре
    2 - Вот так http://php.ru/forum/viewtopic.php?t=%00
     
  18. Vladson, взломал форум =)
     
  19. obsrv

    obsrv Активный пользователь

    С нами с:
    2 окт 2008
    Сообщения:
    238
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    sobachnik
    в другой теме я давал ссылку (можно в инете и самому поискать ;) ).
    емнип: выросла такая атака давно-давно еще из C (а PHP это оно, в частности).
    конструкции форматинга в sprintf (и не только) имели слабость в том, что могло быть переполнение буфера как раз через null-byte. Соответственно записывая бинарные инструкции (после нуллбайта) 'интерпретатору' можно было вставлять свой кусочек EXE (так понятнее).
    Ну, что вспомнил, рассказал (это конечно одно ИЗ и весьма условно рассказаное).
     
  20. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    флоппик
    Ага, сейчас переведу себе на счёт все деньги БГ (и я не имею в виду Бориса Гребенщикова) :)

    Йа мега хацкер, все меня бойтесь :)
     
  21. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Теперь понятнее... А защититься от него...?
     
  22. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    А проверить?
    mysql_real_escape_string его обрабатывает.
     
  23. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Ошибкой в некоторых скриптах является отсутствие проверки имён форм. Сами данные проверяются, а название форм -- нет. И они подставляются сразу в базу.

    Еще одной ошибкой является отсутствие проверки SELECT-формы. Я запросто могу подставить вместо 1го числа -1ое...
     
  24. PeaceDuke

    PeaceDuke Активный пользователь

    С нами с:
    8 ноя 2008
    Сообщения:
    32
    Симпатии:
    0
    А если бабахнуть проверку Яваскриптами (на корректное заполнение полей) а в начале страницы поставить.
    <?php
    $referer=getenv("HTTP_REFERER");
    if (!ereg("www......")) {
    echo "Меня типо хакают\n";
    exit;
    }
    ?>
    толк есть?
     
  25. karakh

    karakh Активный пользователь

    С нами с:
    11 дек 2007
    Сообщения:
    1.344
    Симпатии:
    0
    Нет. От любой проверки яваскриптами есть только один толк - удобство пользователя, которому не надо ждать релоада чтобы узнать что он неправильно заполнил поле. На безопасность это не влияет вообще.