За последние 24 часа нас посетили 26603 программиста и 1511 роботов. Сейчас ищут 875 программистов ...

Безопасен ли код

Тема в разделе "PHP для новичков", создана пользователем brainiac, 5 янв 2011.

  1. brainiac

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

    С нами с:
    5 янв 2011
    Сообщения:
    33
    Симпатии:
    0
    Адрес:
    Новосибирск
    В php я новичёк, на этом месте перестанем ныть и к делу. Написал <s>скрипт</s>.."скрипт", целью которого является авторизация пользователя. Метод передачи данных post. Выглядит обработчик следующим образом:

    PHP:
    1. <?php
    2.     $db=mysql_connect("localhost","lynch","123") or die("Could not connect: ".mysql_error());
    3.     mysql_select_db("getskill",$db) or die ('Cant use foo : '.mysql_error());
    4.    
    5.     $login=false;
    6.     $name='';
    7.     $pass='';
    8.     session_start();
    9.    
    10.     if ($_SESSION['login']==true)
    11.         {
    12.         $login=true;
    13.         $name=$_SESSION['name'];
    14.         $pass=$_SESSION['pass'];
    15.         }
    16.         else
    17.         {
    18.         $name=$_POST['name'];
    19.         $pass=$_POST['pass'];
    20.         $base=mysql_query("SELECT * FROM users WHERE name='$name' AND pass='$pass' ",$db) or die("Invalid query: ".mysql_error());
    21.         if (($numb=mysql_num_rows($base))>0)
    22.             {
    23.             $login=true;
    24.             $_SESSION['login']=$login;
    25.             $_SESSION['name']=$name;
    26.             $_SESSION['pass']=$pass;
    27.             }
    28.             else
    29.             {
    30.             $login=false;
    31.             }
    32.         }
    33.     echo "<html><head>
    34.         <meta http-equiv='Refresh' content='0; URL=index.php'>
    35.         </head></html>";
    36. ?>
    login - булевая переменая, если 1 то залогинились успешно, если 0 то ошибка.

    Если нужно вот сама форма:

    HTML:
    1. <form action="login.php" method="post">
    2.         <input name="name" type="text" value="Введите логин" size="20" maxlength="20" align="center" />
    3.         <input name="pass" type="password" value="12345" size="20" maxlength="20" align="center" />
    4.         <div align="center">
    5.         <input type="submit" value="Войти" />
    6.         <a href="reg.php"><input type="button" value="Регистрация"/></a>
    7.         </div>
    8. </form>

    Вопрос, можно ли (знаю можно точно)...тогда на сколько % эта штука уязвима и несёт опасность и деструктивное действие на планету?
     
  2. Gromo

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

    С нами с:
    24 май 2010
    Сообщения:
    2.786
    Симпатии:
    2
    Адрес:
    Ташкент
    а ты в поле логин поставь одинарную кавычку и убедишься, что эта штука уязвима :)
     
  3. brainiac

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

    С нами с:
    5 янв 2011
    Сообщения:
    33
    Симпатии:
    0
    Адрес:
    Новосибирск
    Ничего не происходит Оо ставлю кавычку, нажимаю Войти, происходит редирект из скрипта на главную с неудачей авторизации...и всё )

    А почему вы так решили? про кавычку
     
  4. Gromo

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

    С нами с:
    24 май 2010
    Сообщения:
    2.786
    Симпатии:
    2
    Адрес:
    Ташкент
    brainiac
    значит скорее всего стоит опция волшебных кавычек
     
  5. karlozzz

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

    С нами с:
    24 окт 2010
    Сообщения:
    430
    Симпатии:
    0
    Адрес:
    Y-OLA
    brainiac
    потому что нужно экранировать кавычки в запросе к БД
     
  6. <?=RPG?>

    <?=RPG?> Активный пользователь

    С нами с:
    19 ноя 2010
    Сообщения:
    451
    Симпатии:
    0
    SELECT * FROM users WHERE name='name' AND pass='' OR 1 = 1 #'
    И все дела. Классический SQL-injection
     
  7. brainiac

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

    С нами с:
    5 янв 2011
    Сообщения:
    33
    Симпатии:
    0
    Адрес:
    Новосибирск
    Дада...обнаружил что были волшебные кавычки, убрал, поставил кавычку, свой косяк понял, спасибо ) Поправил так:
    PHP:
    1.  
    2. <?php
    3.    
    4.     if(empty($_POST['name']) || empty($_POST['pass']))
    5.         {
    6.         echo "Вы должны заполнить все поля! Ждём 3 секунды...";
    7.         echo "<html><head>
    8.        <meta http-equiv='Refresh' content='3; URL=index.php'>
    9.        </head></html>";
    10.         exit;
    11.         }
    12.    
    13.     $db=mysql_connect("localhost","lynch","123") or die("Could not connect: ".mysql_error());
    14.     mysql_select_db("getskill",$db) or die ('Cant use foo : '.mysql_error());
    15.    
    16.     $login=false;
    17.     $name='';
    18.     $pass='';
    19.     session_start();
    20.    
    21.     if ($_SESSION['login']==true)
    22.         {
    23.         $login=true;
    24.         $name=$_SESSION['name'];
    25.         $pass=$_SESSION['pass'];
    26.         }
    27.         else
    28.         {
    29.         $name=$_POST['name'];
    30.         $pass=$_POST['pass'];
    31.         $name=trim(mysql_real_escape_string($name));
    32.         $pass=trim(mysql_real_escape_string($pass));
    33.         $base=mysql_query("SELECT * FROM `users` WHERE `name`='$name' AND `pass`='$pass' ",$db) or die("Invalid query: ".mysql_error());
    34.         if (($numb=mysql_num_rows($base))>0)
    35.             {
    36.             $login=true;
    37.             $_SESSION['login']=$login;
    38.             $_SESSION['name']=$name;
    39.             $_SESSION['pass']=$pass;
    40.             }
    41.             else
    42.             {
    43.             $login=false;
    44.             }
    45.         }
    46.     echo "<html><head>
    47.         <meta http-equiv='Refresh' content='0; URL=index.php'>
    48.         </head></html>";
    49. ?>
    50.  
    поставил проверку пустых полей, расстановку слэшей и название столбцов в кавычки взял.

    Что тут ещё нехорошего можно устроить? И ещё вопрос касательно логики этого всего: может быть можно как-нибудь без этого обработчика с постоянным редиректом на главную...там ajax может поможет или может есть ещё более простые варианты? Спасибо.[/php]

    А этого не понял...если не подскажите как такую строку сделать и что такое or 1= 1 # - пойду убьюсь...или читать )

    А ещё лучше слэшировать или сразу "подготовленными выражениями" пользоваться? Второе я не пробовал...ещё
     
  8. <?=RPG?>

    <?=RPG?> Активный пользователь

    С нами с:
    19 ноя 2010
    Сообщения:
    451
    Симпатии:
    0
    Этот запрос выполнится на сервере если в качестве пароля взять последовательность ' OR 1 = 1 #

    К чему это приведет: будут выбраны все записи из таблицы невзирая на проверки.
     
  9. brainiac

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

    С нами с:
    5 янв 2011
    Сообщения:
    33
    Симпатии:
    0
    Адрес:
    Новосибирск
    Спасибо огромное! Кстати зная логин можно было зайти без пароля так: brainiac'# , но уже не зайти ибо спец символы экранируются...Вопрос: одного экранирования данных перед sql запросом хватит? Или дополнительно проверять нужно ещё на специальные слова, используемые в sql ?
     
  10. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Теперь при включенном magic_quotes экранироваться будет дважды. Я бы сделал так:
    PHP:
    1. <?php
    2. $name = (isset($_POST['name'])) ? escapeStr(trim($_POST['name']), $db) : '';
    3. // ...
    4. function escapeStr($str = '', $db = false) {
    5.       $str = stripslashes($str);
    6.    $str = ($db) ? mysql_real_escape_string($str, $db) : mysql_escape_string($str);
    7.    return($str);
    8. }
    9. ?>
     
  11. brainiac

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

    С нами с:
    5 янв 2011
    Сообщения:
    33
    Симпатии:
    0
    Адрес:
    Новосибирск
    Код (Text):
    1.  
    2. Если  в ПОСТ есть name то присваиваем $name результат функции, если нет то присваимваем пустоту...
    3. Точно также для других..
    4.  
    5. Функция с 2-мя аргументами...
    6. Если волшебные включены то удаляем экранирование.
    7. Если соединение с базой есть то переменной $str присваиваем еёже с экранированными спец символами, если соединения нет то экранируем все спец символы.
    8. Возвращаем str.
    Я так перевёл? Только я не понял почему мы используем функцию до её определения...И ещё не понял последние строки где $db проверяем...Почему нельзя просто убрать всё экранирование если включено волшебство и заэкранировать поновой.

    И ещё момент: каков механизм присваивания аргументов в функции?
    (trim($_POST['name']) -> ($str='')
    $db -> ($db=false).
    Что происходит когда мы это всё так подставляем? Просто $str присваивается '' а потом trim($_POST['name'] ? И аналогично db..
    PS просто в том языке который я знаю это дало бы ошибку ) впрочем т.к. он косячный.

    Спасибо за метод, интересно )
     
  12. Padaboo

    Padaboo Старожил
    Команда форума Модератор

    С нами с:
    26 окт 2009
    Сообщения:
    5.242
    Симпатии:
    1
  13. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    Можно. Просто функция написана так, чтобы корректно отработала если, например, по каким-то причинам её вызов будет до установления соединения с б.д. Ну или, например, забыли передать указатель на соединение с б.д.
    Если соединение с б.д. есть - экранирование происходит функцией mysql_real_escape_string(), которая учитывает кодировку соединения с б.д. Иначе - функцией mysql_escape_string(). Из описания функции mysql_escape_string():
    По поводу передаваемых аргументов. Строка
    PHP:
    1. <?php
    2. $name = (isset($_POST['name'])) ? escapeStr(trim($_POST['name']), $db) : '';
    идентична
    PHP:
    1. <?php
    2. if(isset($_POST['name'])) {
    3.    $name = trim($_POST['name']);
    4.    $name = escapeStr($name, $db);
    5. } else
    6.    $name = '';
    То есть
    $newVar = functionOne(functionTwo($var));
    сделает следующее: сперва отработает функция functionTwo(), а потом результат её работы (то, что эта функция вернёт) передастся в качестве аргумента в функцию functionOne().
    По поводу того, как функция принимает аргументы. Когда пишем:
    functionName($varOne = '', $varTwo = false) {
    ...
    }
    означает, что переменная $varOne "по умолчанию", так сказать, будет равна пустой строке, а $varTwo - false. То есть эти значения присвоятся переменным в функции, если вызвать функцию без аргументов:
    functionName();
    Если вызвать с одним аргументом:
    functionName('строка');
    то переменной $varOne будет присвоено значение 'строка', а у переменной $varTwo будет значение по умолчанию (false).
    В php это не важно, где определение функции, а где её вызов.
     
  14. brainiac

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

    С нами с:
    5 янв 2011
    Сообщения:
    33
    Симпатии:
    0
    Адрес:
    Новосибирск
    o_O ожидал какой-нить маленький такой ответик, а тут прям разжевали всё ) Даже сказать нечего, все вопросы отпали ) Огромное (как моя улыбка) спасибо, вообще привык кнопочку нужную кликать...но тут жаль нет. Много нового и полезного узнал для себя, ещё узнал, что на форумах есть хорошие люди, спасибо вам, всем отписавшимся в этом топике.

    PS про логику тернарного оператора я знал, подсмотрел в гугле после того кода. )

    Padaboo, не увидел, спасибо что поправили.

    Всё, это конец темы.