За последние 24 часа нас посетили 16583 программиста и 1578 роботов. Сейчас ищут 889 программистов ...

Безопасность

Тема в разделе "PHP для новичков", создана пользователем Panich, 2 авг 2012.

  1. Panich

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

    С нами с:
    10 май 2011
    Сообщения:
    548
    Симпатии:
    0
    Адрес:
    Ростов-Москва
    Посидел над скриптиком безопасности.Кто соображает больше-дайте совет!
    Код (Text):
    1. <?php
    2. session_start();
    3. include ("bd_hell.php");
    4. if (!empty($_POST['login']) and !empty($_POST['name']))
    5. {
    6.     $login = mysql_real_escape_string(trim($_POST['login']));
    7.     $login = htmlspecialchars($login);
    8.     if(get_magic_quotes_gpc())
    9.     {
    10.     $login = stripslashes($login);
    11.     }
    12.     $pass = mysql_real_escape_string(trim($_POST['pass']));
    13.     $pass = htmlspecialchars($pass);
    14.     if(get_magic_quotes_gpc())
    15.     {
    16.     $pass = stripslashes($pass);
    17.     }
    18.     if(!preg_match("/^[a-zA-Z0-9_\.\-]$/",$login))
    19.     {
    20.     header("Location: index.html");
    21.     }
    22.     else
    23.     {
    24.         if(!preg_match("/^[a-zA-Z0-9_\.\-]$/",$pass))
    25.         {
    26.         header("Location: index.html");
    27.         }
    28.         else
    29.         {
    30.        
    31.             $sql = "SELECT * FROM `userlist` WHERE `login`='$login' AND `pass`='$pass' LIMIT 1";
    32.             $result = mysql_query($sql, $db)or die("Ошибка в запросе: " . mysql_error());
    33.             if (!$result)
    34.             {
    35.             echo "ошибка - ".mysql_error()."<br>";
    36.             echo $sql;
    37.             exit();
    38.             }
    39.             else
    40.             {
    41.                 $myrow = mysql_fetch_assoc($result);
    42.                 if(!empty($myrow['id']))
    43.                 {
    44.                 $_SESSION['id'] = $id;
    45.                 header("hell.php");
    46.                 }
    47.                 else
    48.                 {
    49.                 header("Location: index.html");
    50.                 }
    51.             }
    52.         }
    53.     }  
    54. }
    55. else
    56. {
    57. header("Location: index.html");
    58. }        
    59. if (isset($_SESSION['id']))
    60. {
    61.     $id = intval(mysql_real_escape_string($_SESSION['id']));
    62.     if (!preg_match("|^[\d]+$|", $id))    
    63.     {            
    64.     header("Location: index.html");
    65.     }
    66.     else
    67.     {
    68.     $login = mysql_real_escape_string(trim($_SESSION['login']));
    69.     $login = htmlspecialchars($login);
    70.     if(get_magic_quotes_gpc())
    71.     {
    72.     $login = stripslashes($login);
    73.     }
    74.     $pass = mysql_real_escape_string(trim($_SESSION['pass']));
    75.     $pass = htmlspecialchars($pass);
    76.     if(get_magic_quotes_gpc())
    77.     {
    78.     $pass = stripslashes($pass);
    79.     }
    80.     $sql = "SELECT * FROM `userlist` WHERE `login`='$login' AND `pass`='$pass' LIMIT 1";
    81.     $result = mysql_query($sql, $db)or die("Ошибка в запросе: " . mysql_error());
    82.     if (!$result)
    83.     {
    84.     echo "ошибка - ".mysql_error()."<br>";
    85.     echo $sql;
    86.     exit();
    87.     }
    88.     else
    89.     {
    90.         $myrow = mysql_fetch_assoc($result);
    91.         if(empty($myrow['id']))
    92.         {
    93.         header("Location: index.html");
    94.         }
    95.     }
    96. }              
    97. else            
    98. {
    99. header("Location: index.html");
    100. }
    101. ?>
    В частности у меня выдаёт ошибки:
    Код (Text):
    1. Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at Z:\home\localhost\www\rosneft\enterAd.php:1) in Z:\home\localhost\www\rosneft\enterAd.php on line 2
    2. Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at Z:\home\localhost\www\rosneft\enterAd.php:1) in Z:\home\localhost\www\rosneft\enterAd.php on line 2
    3. Warning: Cannot modify header information - headers already sent by (output started at Z:\home\localhost\www\rosneft\enterAd.php:1) in Z:\home\localhost\www\rosneft\enterAd.php on line 56
    4. Warning: Cannot modify header information - headers already sent by (output started at Z:\home\localhost\www\rosneft\enterAd.php:1) in Z:\home\localhost\www\rosneft\enterAd.php on line 99
    Спасибо за потраченное время...
     
  2. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Во-первых, если хочешь учесть то, что на сервере возможно включены magic_quotes_gpc, то делаешь это не в той последовательности. Сперва нужно проверить и сделать stripslashes при необходимости, а потом уже делать mysql_real_escape_string().
    Во-вторых, чтобы не повторять этот фрагмент кода для каждого параметра запроса - можно, например, написать функцию, которая будет это делать:
    Код (PHP):
    1. <?php
    2. function myEscape($str = '') {
    3.     if(get_magic_quotes_gpc())
    4.         $str = stripslashes($str);
    5.     return(mysql_real_escape_string($str));
    6. }
    7. ?>
    и потом просто ей всё эскейпить:
    Код (PHP):
    1. <?php
    2. // ...
    3. $login = myEscape($_POST['login']);
    4. // ...
    5. ?>
    В-третьих, через htmlspecialchars() обычно пропускают не при записи в б.д., а при выводе из б.д. в браузер. В принципе, это не принципиально я думаю, но обычно так делают - типа чтобы в б.д. хранились оригинальные данные, какими их ввёл пользователь.
    В-четвёртых, проверку на допустимые в логине символы (a-zA-Z0-9_.-) - это на мой (и не только мой) взгляд лишнее. Мне кажется, пусть пользователи называют себя как им нравится. Хотят русскими буквами - ну и пусть русскими пишут, какя разница? Но это дело твоё, конечно. Для безопасности роли не играет по идее.
    В-пятых, после того, как делаешь переадресацию header Location - нужно учитывать, что отправив этот заголовок скрипт будет выполняться дальше. Да, в браузере страница не отобразится, но скрипт отработает до конца и выполнятся все инструкции, которые там дальше идут. Например, что-то может добавиться в б.д., если там есть вставка данных. Для php команда header('Location: index.html'); - это как и любая другая обычная команда, тот же echo(), например. Он выполнит её (отправит заголовок браузеру) и продолжит дальше выполнять следующие команды. Если ты хочешь, чтобы после отправки заголовка на переадресацию дальше скрипт не выполнялся - нужно после header ставить exit;
    Код (PHP):
    1.       if(!preg_match("/^[a-zA-Z0-9_\.\-]$/",$pass))
    2.       {
    3.          header("Location: index.html");
    4.          exit;
    5.       } 
    В-шестых, тримить (trim()) пароль я лично бы не стал - может пользователь хочет, чтобы его пароль начинался с пробела? :) Ну и пусть начинается с пробела. Зато в б.д. принято писать хэш пароля, а не в чистом виде. Впрочем, это скорее всего, тоже мелочи и не принципиально, но обычно делают так. Причём как правило не просто стандартный хэш типа md5, а что-то вроде хэш от хэша с солью :) Ну как-то так, например:
    Код (PHP):
    1. $salt = 'Это соль :-)';
    2. $pass = md5(md5($_POST['pass']) . $salt); 
    В-седьмых, вот это вот:
    Код (PHP):
    1. or die("Ошибка в запросе: " . mysql_error()); 
    на рабочем сайте в интернете - вообще ни к чему. Это нужно на период разработки и отладки скрипта. Когда скрипт готов и выложен в интернет - в нём не должно быть такого. Я знаю две причины: одна из них - это то, что это просто какая-то лишняя, пугающая и не понятная пользователям информация, которая к тому же никак не оформлена, а просто сверху появятся чёрные буквы на белом фоне. Пользователю это уж точно не надо :) Во вторых, это может здорово облегчить жизнь потенциальным взломщикам твоего сайта. Особенно вместе вот с этим:
    Код (PHP):
    1.          echo "ошибка - ".mysql_error()."<br>";
    2.          echo $sql;
    3.          exit(); 
    Увидев текст получившегося запроса и сообщение об ошибке, подобрать заветную фразу чтобы всё поломалось окончательно будет легче :)

    Добавлено спустя 14 минут 59 секунд:
    Я обычно пишу свою функцию, которая вызывается, если запрос не прошёл, и передаю ей три аргумента: текст запроса, текст сообщения об ошибке и третьим параметром - нужно ли останавливать работу скрипта:
    Код (PHP):
    1. function db_error($sql = '', $err = '', $stop = false) {
    2.     if(Config::$debug_mode) {
    3.         // Режим отладки. Вываливаем сообщение об ошибке запроса на экран
    4.     } else {
    5.         // Рабочий режим.
    6.         // Здесь мы записываем информацию о произошедшей ошибке в лог
    7.         // И проверяем, нужно ли останавливать выполнение скрипта
    8.         if($stop) {
    9.             require('site_error.html');
    10.             exit;
    11.         }
    12.     }
    13. } 
    Соответственно, вызываться может так:
    Код (PHP):
    1. $sql = "SELECT * FROM `users`";
    2. $res = mysql_query($sql, $db) or db_error($sql, mysql_error($db), true); 
    В данном случае я посчитал, что это был важный запрос, без которого дальнейшее выполнение скрипта бессмысленно. Поэтому я передаю третьим параметром true - чтобы функция вывела на экран содержимое файла site_error.html и остановила выполнение скрипта. В файле site_error.html может храниться какая-нить оформленная и задизайненная страничка с сообщением о том, что на сайте что-то произошло. Там могут быть какие-то полезные ссылки - например, перейти на главную, вернуться назад или отправить письмо админу сайта.

    Добавлено спустя 3 минуты 47 секунд:
    UPD!
    Блин, правку отключили :)
    В общем я там в функции db_error() не правильно написал. Надо было так:
    function db_error($sql = '', $err = '', $stop = false) {
    if(Config::$debug_mode) {
    // Режим отладки. Вываливаем сообщение об ошибке запроса на экран
    } else {
    // Рабочий режим.
    // Здесь мы записываем информацию о произошедшей ошибке в лог
    // И проверяем, нужно ли останавливать выполнение скрипта
    if($stop) {
    require('site_error.html');
    }
    }
    if($stop)
    exit;
    }

    Добавлено спустя 1 минуту 47 секунд:
    :D
    И опять блин, правку отключили :)))
    Код (PHP):
    1. function db_error($sql = '', $err = '', $stop = false) {
    2.     if(Config::$debug_mode) {
    3.         // Режим отладки. Вываливаем сообщение об ошибке запроса на экран
    4.     } else {
    5.         // Рабочий режим.
    6.         // Здесь мы записываем информацию о произошедшей ошибке в лог
    7.         // И проверяем, нужно ли останавливать выполнение скрипта
    8.         if($stop) {
    9.             require('site_error.html');
    10.         }
    11.     }
    12.     if($stop)
    13.         exit;
    14. } 
    Добавлено спустя 3 минуты 38 секунд:
    А по поводу твоей ошибки
    - это говорит о том, что где-то уже начат вывод страницы, а ты пытаешься отправить заголовок. Например, такое может быть, если файл со скриптом сохранён в кодировке UTF-8 с BOM (надо сохранить в UTF-8 без BOM). Также такое может выскочить, если где-то перед <?php есть какой-нибудь символ, который ты не заметил - достаточно одного пробела.
     
  3. Panich

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

    С нами с:
    10 май 2011
    Сообщения:
    548
    Симпатии:
    0
    Адрес:
    Ростов-Москва
    Ох!!!Вот это ответ...тут и добавить нечего уже!Спасибо большое!!!
    Только вот вопрос:что это вообще такое - BOM!!!Я пробовал без BOM сохранять и у меня тогда вместо русских букв иероглифы...
     
  4. Your

    Your Старожил

    С нами с:
    2 июл 2011
    Сообщения:
    4.074
    Симпатии:
    7
    Код (PHP):
    1. public static function injects($injects,$bool=false) {
    2.         if(self::$mysqli && !$bool) {
    3.             return mysqli_real_escape_string(self::$mysqli,$injects);
    4.         } else if(version_compare(PHP_VERSION,'5.3.0','<')) {
    5.             return get_magic_quotes_gpc()?$injects:addslashes($injects);
    6.         } else {
    7.             return addslashes($injects);
    8.         }
    9.     return false;
    10.     } 
    Ну еще можно таким путем пойти.
     
  5. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    это же срань господня! "без BOM не работает" ))))
    во первых убедись, что твой файл таки в UTF-8 сохранился, а не в какой-нибудь 1251
    во вторых проверь что браузер получает заголовок
    Код (Text):
    1. Content-Type: text/html; charset=UTF-8
     
  6. Panich

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

    С нами с:
    10 май 2011
    Сообщения:
    548
    Симпатии:
    0
    Адрес:
    Ростов-Москва
    Your,спасибо,применяю к работе!
    artoodetoo,да в utf-8,проверял 1000 раз!Щас ещё поковыряю...
    Так в чём разнице между с BUM т без BOM?

    Всё сделал как Вы советовали:пользователь вводит логин и пароль-передаётся обработчику,который если "плохо",то на index.html,а если нормально,то на нужную страницу-на нужной страницу проверяю:
    Код (Text):
    1. if (isset($_SESSION['id']))
    ,но всё время проверяет условие "else"-как быть?В чём причина может скрываться?
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    а на "нужной странице" до этой строки вызывается session_start() ?
    иногда дурацкие вопросы не такие уж и дурацкие
     
  8. Panich

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

    С нами с:
    10 май 2011
    Сообщения:
    548
    Симпатии:
    0
    Адрес:
    Ростов-Москва
    ...да!Но хотелось бы,что именно на этом и засыпался и уже продолжил писать дальше...)))
     
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
  10. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    http://ru.wikipedia.org/wiki/BOM
    В общем это такой спецсимвол, который текстовый редактор поставит самым-самым первым в файле, он-то и начнёт отправку основного содержимого ответа ещё до того, как ты заголовки пытаешься отправить.
     
  11. Panich

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

    С нами с:
    10 май 2011
    Сообщения:
    548
    Симпатии:
    0
    Адрес:
    Ростов-Москва
    Ага!Спасибо!!!
     
  12. atm87

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

    С нами с:
    3 авг 2012
    Сообщения:
    2
    Симпатии:
    0
    sobachnik
    Спасибо за ответ. Почитал твою статью и много узнал нового. +1 к твоей карме.;)))