query - php mysql select




Почему я не должен использовать функции mysql_*в PHP? (10)

Каковы технические причины, по которым нельзя использовать функции mysql_* ? (например, mysql_query() , mysql_connect() или mysql_real_escape_string() )?

Почему я должен использовать что-то еще, даже если они работают на моем сайте?

Если они не работают на моем сайте, почему я получаю такие ошибки, как

Предупреждение: mysql_connect (): нет такого файла или каталога


Простота использования

Аналитические и синтетические причины уже упоминались. Для новичков есть более существенный стимул прекратить использование устаревших функций mysql_.

Современные API баз данных проще в использовании.

В основном это связанные параметры, которые могут упростить код. И с share переход на PDO не слишком труден.

Переписывание большей кодовой базы за один раз, однако, требует времени. Raison d'être для этой промежуточной альтернативы:

Эквивалентные функции pdo_ * вместо mysql_ *

Используя < pdo_mysql.php >, вы можете переключаться со старых функций mysql_ с минимальными усилиями . Это добавляет pdo_ функции pdo_ которые заменяют их аналоги mysql_ .

  1. Просто include_once( "pdo_mysql.php" ); в каждом скрипте вызова, который должен взаимодействовать с базой данных.

  2. Удалите mysql_ функции mysql_ везде и замените его на pdo_ .

    • mysql_ connect() становится pdo_ connect()
    • mysql_ query() становится pdo_ query()
    • mysql_ num_rows() становится pdo_ num_rows()
    • mysql_ insert_id() становится pdo_ insert_id()
    • mysql_ fetch_array() становится pdo_ fetch_array()
    • mysql_ fetch_assoc() становится pdo_ fetch_assoc()
    • mysql_ real_escape_string() становится pdo_ real_escape_string()
    • и так далее...

  3. Ваш код будет работать одинаково и в основном будет выглядеть одинаково:

    include_once("pdo_mysql.php"); 
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");  
    
    while ($row = pdo_fetch_assoc($result)) {
        print "$row[title] - $row[html]";
    }

И вуаля.
Ваш код использует PDO.
Теперь пришло время фактически использовать это.

Связанные параметры могут быть просты в использовании

Вам просто нужен менее громоздкий API.

pdo_query() добавляет очень легкую поддержку для связанных параметров. Преобразовать старый код просто:

Переместите свои переменные из строки SQL.

  • Добавьте их в качестве параметров функции, разделенных запятыми, в pdo_query() .
  • Ставить вопросительные знаки ? в качестве заполнителей, где переменные были раньше.
  • Избавьтесь от одиночных кавычек, которые ранее заключали в себе строковые значения / переменные.

Преимущество становится более очевидным для более длинного кода.

Часто строковые переменные не просто интерполируются в SQL, а объединяются с экранированием вызовов между ними.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

С ? заполнители подали заявку, вам не нужно беспокоиться об этом:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Помните, что pdo_ * все еще позволяет либо .
Просто не экранируйте переменную и связывайте ее в одном запросе.

  • Функция заполнителя обеспечивается настоящим PDO за ним.
  • Таким образом также допускается :named заполнители списки позже

Более того, вы можете безопасно передавать переменные $ _REQUEST [] за любым запросом. Когда отправленные поля <form> соответствуют структуре базы данных, она становится еще короче:

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);

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

Исправить или удалить любую функцию oldschool sanitize()

Как только вы преобразовали все вызовы mysql_ в pdo_query со связанными параметрами, удалите все избыточные вызовы pdo_real_escape_string .

В частности, вы должны исправить любые функции sanitize или clean или clean_data или clean_data как объявлено датированными учебниками в одной или другой форме:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

Самая вопиющая ошибка здесь - отсутствие документации. Что еще важнее, порядок фильтрации был в неправильном порядке.

  • Правильный порядок был бы следующим: устарелое stripslashes как внутреннего вызова, затем trim , затем strip_tags , htmlentities для выходного контекста и, наконец, только _escape_string поскольку его приложение должно непосредственно предшествовать промежуточному анализу SQL.

  • Но в качестве первого шага просто избавьтесь от вызова _real_escape_string .

  • Возможно, вам придется сохранить оставшуюся часть функции sanitize() если ваша база данных и поток приложений ожидают HTML-контекстно-безопасные строки. Добавьте комментарий, что отныне он применяет только HTML.

  • Обработка строк / значений делегируется PDO и его параметризованным операторам.

  • Если в вашей функции дезинфекции было упомянуто о stripslashes() , это может указывать на более высокий уровень контроля.

    Историческая справка о magic_quotes. Эта функция по праву считается устаревшей. Однако часто это неправильно изображается как сбойная функция безопасности . Но magic_quotes - такая же неудачная функция безопасности, как и теннисные мячи, как источник питания. Это просто не было их целью.

    Первоначальная реализация в PHP2 / FI вводила это явно, просто « кавычки будут автоматически экранированы, что упростит передачу данных формы непосредственно в запросы msql ». Примечательно, что это было безопасно для использования с mSQL , так как он поддерживал только ASCII.
    Затем PHP3 / Zend заново ввел magic_quotes для MySQL и неправильно его документировал. Но изначально это была просто удобная функция , не предназначенная для безопасности.

Чем отличаются готовые заявления

Когда вы скремблируете строковые переменные в запросы SQL, вам не просто становится сложнее следовать. MySQL также постарается снова разделить код и данные.

Инъекции SQL просто происходят, когда данные попадают в контекст кода . Сервер базы данных не может позже определить, где PHP изначально склеивал переменные между предложениями запроса.

С помощью связанных параметров вы разделяете SQL-код и значения SQL-контекста в вашем PHP-коде. Но он не зацикливается снова (за исключением PDO :: EMULATE_PREPARES). Ваша база данных получает неизменные команды SQL и значения переменных 1: 1.

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

Помните, что привязка параметров не является волшебным универсальным решением против всех SQL-инъекций. Он обрабатывает наиболее распространенное использование для данных / значений. Но он не может указать имя столбца / идентификаторы таблицы, помочь с построением динамического предложения или просто списком значений массива.

Использование гибридного PDO

Эти pdo_* обёртки pdo_* делают API-интерфейс для удобного программирования. (Это в значительной степени то, MYSQLI мог бы быть MYSQLI , если бы не смещение сигнатур уникальной функции). Они также чаще всего выставляют настоящий PDO.
Перезапись не должна останавливаться на использовании новых имен функций pdo_. Вы можете по очереди переходить каждый pdo_query () в простой вызов $ pdo-> prepare () -> execute ().

Однако лучше начать с упрощения. Например, общий выбор результатов:

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Может быть заменен только итерацией foreach:

foreach ($result as $row) {

Или, что еще лучше, прямой и полный поиск массивов:

$result->fetchAll();

В большинстве случаев вы получите более полезные предупреждения, чем обычно выдают PDO или mysql_ после неудачных запросов.

Другие опции

Таким образом, мы надеемся, что это наглядно продемонстрировало некоторые практические причины и полезный путь для mysql_ от mysql_ .

Просто переключиться на pdo не совсем так. pdo_query() также является только pdo_query() интерфейсом.

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

Несмотря на то, что он соответствует категории «самая простая вещь из всех возможных», он также по-прежнему является очень экспериментальным кодом. Я просто написал это на выходных. Однако существует множество альтернатив. Просто Google для PHP абстракции базы данных и просматривать немного. Для таких задач всегда было и будет много отличных библиотек.

Если вы хотите еще больше упростить взаимодействие с базой данных, стоит попробовать такие картографы, как Paris/Idiorm . Точно так же, как никто не использует более мягкий DOM в JavaScript, вам не нужно сейчас присматривать за сырым интерфейсом базы данных.


Говоря о технических причинах, их всего несколько, крайне специфичных и редко используемых. Скорее всего, вы никогда не будете использовать их в своей жизни.
Может быть, я слишком невежественен, но у меня никогда не было возможности использовать такие вещи, как

  • неблокирующие, асинхронные запросы
  • хранимые процедуры, возвращающие несколько результирующих наборов
  • Шифрование (SSL)
  • компрессия

Если они вам нужны - это, без сомнения, технические причины для перехода от расширения mysql к чему-то более стильному и современному.

Тем не менее, есть также некоторые нетехнические проблемы, которые могут сделать ваш опыт немного сложнее

  • Дальнейшее использование этих функций в современных версиях PHP вызовет уведомления устаревшего уровня. Их просто можно отключить.
  • в отдаленном будущем они могут быть удалены из сборки PHP по умолчанию. Не так уж и страшно, так как mydsql ext будет перемещен в PECL, и каждый хостер будет рад скомпилировать с ним PHP, так как они не хотят терять клиентов, чьи сайты работали десятилетиями.
  • сильное сопротивление со стороны сообщества . Каждый раз, когда вы упоминаете эти честные функции, вам говорят, что они находятся под строгим табу.
  • Будучи обычным пользователем PHP, скорее всего, ваша идея использовать эти функции подвержена ошибкам и ошибочна. Просто из-за всех этих многочисленных учебников и руководств, которые научат вас неправильному пути. Не сами функции - я должен это подчеркнуть - а то, как они используются.

Эта последняя проблема является проблемой.
Но, на мой взгляд, предлагаемое решение тоже не лучше.
Мне кажется слишком идеалистической мечтой о том, что все эти пользователи PHP сразу научатся правильно обрабатывать запросы SQL. Скорее всего, они просто изменили бы mysql_ * на mysqli_ * механически, оставив подход тот же . Тем более, что mysqli делает использование готовых заявлений невероятно болезненным и хлопотным.
Не говоря уже о том, что собственных подготовленных операторов недостаточно для защиты от SQL-инъекций, и ни mysqli, ни PDO не предлагают решения.

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

Кроме того, есть несколько ложных или несущественных причин, таких как

  • Не поддерживает хранимые процедуры (мы использовали mysql_query("CALL my_proc"); целую вечность)
  • Не поддерживает транзакции (как указано выше)
  • Не поддерживает множественные заявления (кому они нужны?)
  • Не в активном развитии (ну и что? Это как-то влияет на тебя ?)
  • Отсутствует интерфейс OO (для его создания требуется несколько часов)
  • Не поддерживает подготовленные операторы или параметризованные запросы

Последний интересный момент. Хотя mysql ext не поддерживает нативно подготовленные операторы, они не требуются для безопасности. Мы можем легко подделать подготовленные операторы, используя заполнители, обработанные вручную (как это делает PDO):

function paraQuery()
{
    $args  = func_get_args();
    $query = array_shift($args);
    $query = str_replace("%s","'%s'",$query); 

    foreach ($args as $key => $val)
    {
        $args[$key] = mysql_real_escape_string($val);
    }

    $query  = vsprintf($query, $args);
    $result = mysql_query($query);
    if (!$result)
    {
        throw new Exception(mysql_error()." [$query]");
    }
    return $result;
}

$query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);

Вуаля , все параметризовано и безопасно.

Но хорошо, если вам не нравится красная рамка в руководстве, возникает проблема выбора: mysqli или PDO?

Ну, ответ будет следующим:

  • Если вы понимаете необходимость использования уровня абстракции базы данных и ищете API для его создания, mysqli - очень хороший выбор, поскольку он действительно поддерживает многие специфичные для mysql функции.
  • Если, как и подавляющее большинство PHP-пользователей, вы используете необработанные вызовы API прямо в коде приложения (что, по сути, является неправильной практикой), PDO - единственный выбор , поскольку это расширение претендует на то, чтобы быть не просто API, а скорее полу-DAL, все еще неполный, но предлагает много важных функций, с двумя из них отличает PDO от mysqli:

    • в отличие от mysqli, PDO может связывать заполнители по значению , что делает динамически построенные запросы выполнимыми без нескольких экранов довольно грязного кода.
    • в отличие от mysqli, PDO всегда может вернуть результат запроса в простом обычном массиве, тогда как mysqli может сделать это только при установке mysqlnd.

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

Тем не менее, все, кто говорит о расширениях, всегда упускают два важных факта о Mysqli и PDO:

  1. Подготовленное заявление не является серебряной пулей . Существуют динамические идентификаторы, которые нельзя связать с помощью подготовленных операторов. Существуют динамические запросы с неизвестным количеством параметров, что затрудняет построение запросов.

  2. Ни mysqli_ *, ни функции PDO не должны были появиться в коде приложения. Между ними и кодом приложения
    должен быть уровень абстракции , который будет выполнять всю грязную работу по связыванию, зацикливанию, обработке ошибок и т. Д. Внутри, делая код приложения СУХИМЫМ и чистым. Особенно для сложных случаев, таких как динамическое построение запросов.

Таким образом, просто переключиться на PDO или MySQL не достаточно. Нужно использовать ORM, или построитель запросов, или любой другой класс абстракции базы данных вместо вызова сырых функций API в их коде.
И наоборот - если у вас есть уровень абстракции между кодом приложения и MySQL API - на самом деле не имеет значения, какой движок используется. Вы можете использовать mysql ext до тех пор, пока он не устареет, а затем легко переписать ваш класс абстракции на другой движок, оставив весь код приложения без изменений.

Вот несколько примеров, основанных на моем классе safemysql, чтобы показать, каким должен быть такой класс абстракции:

$city_ids = array(1,2,3);
$cities   = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);

Сравните эту единственную строку с количеством кода, который вам понадобится в PDO .
Затем сравните с сумасшедшим количеством кода, который вам понадобится, с необработанными инструкциями, написанными на Mysqli. Обратите внимание, что обработка ошибок, профилирование, ведение журнала запросов уже встроены и работают.

$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);

Сравните это с обычными вставками PDO, когда каждое имя поля повторяется шесть-десять раз - во всех этих многочисленных именованных заполнителях, привязках и определениях запросов.

Другой пример:

$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);

Вы вряд ли найдете пример для PDO, чтобы справиться с таким практическим случаем.
И это будет слишком многословно и, скорее всего, небезопасно.

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


Потому что (среди прочих причин) гораздо сложнее обеспечить очистку входных данных. Если вы используете параметризованные запросы, как в случае с PDO или mysqli, вы можете полностью избежать риска.

Как пример, кто-то может использовать "enhzflep); drop table users" в качестве имени пользователя. Старые функции позволяют выполнять несколько операторов на запрос, поэтому что-то вроде этого мерзкого баггера может удалить всю таблицу

Если бы кто-то использовал PDO mysqli, имя пользователя в конечном итоге оказалось бы "enhzflep); drop table users" .

Смотрите bobby-tables.com .


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

При использовании mysql_* функций, вы должны помнить, чтобы запустить пользовательские параметры через mysql_real_escape_string() . Если вы забыли только в одном месте или вам удалось избежать только части ввода, ваша база данных может подвергнуться атаке.

Использование подготовленных операторов PDO или mysqli сделает так, чтобы подобные ошибки программирования были более сложными.


Функции , которые , как похожи на это mysql_connect() , mysql_query() типа , являются предыдущие версии PHP (т.е. PHP 4) функции и сейчас не используется.

Они заменяются mysqli_connect() , так mysqli_query() же в последнем PHP5.

Это причина ошибки.


Эти mysql_ функции:

  1. устарели - они больше не поддерживаются
  2. не позволяют легко переходить на другую базу данных
  3. не поддерживают подготовленные заявления, следовательно
  4. поощрять программистов использовать конкатенацию для построения запросов, что приводит к уязвимостям внедрения SQL

Этот ответ написан, чтобы показать, насколько тривиально обходить плохо написанный код проверки пользователя PHP, как (и с помощью чего) эти атаки работают и как заменить старые функции MySQL защищенным подготовленным оператором - и, в основном, почему пользователи (вероятно, с большим количеством представителей) лают на новых пользователей, задающих вопросы, чтобы улучшить их код.

Прежде всего, пожалуйста, не стесняйтесь создавать эту тестовую базу данных MySQL (я назвал мой Prep):

mysql> create table users(
    -> id int(2) primary key auto_increment,
    -> userid tinytext,
    -> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

После этого мы можем перейти к нашему PHP-коду.

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

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }

    $database='prep';
    $link=mysql_connect('localhost', 'prepared', 'example');
    mysql_select_db($database) or die( "Unable to select database");

    $sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
    //echo $sql."<br><br>";
    $result=mysql_query($sql);
    $isAdmin=false;
    while ($row = mysql_fetch_assoc($result)) {
        echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
        $isAdmin=true;
        // We have correctly matched the Username and Password
        // Lets give this person full access
    }
    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }
    mysql_close($link);

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

На первый взгляд кажется вполне законным.

Пользователь должен ввести логин и пароль, верно?

Молодец, не входи в следующее:

user: bob
pass: somePass

и представить его.

Вывод следующий:

You could not be verified. Please try again...

Супер! Работая как положено, теперь давайте попробуем ввести действительное имя пользователя и пароль:

user: Fluffeh
pass: mypass

Удивительно! Привет пятерки со всех сторон, код правильно проверен админом. Это идеально!

Ну не совсем. Допустим, пользователь умный маленький человек. Допустим, человек - это я.

Введите в следующем:

user: bob
pass: n' or 1=1 or 'm=m

И вывод:

The check passed. We have a verified admin!

Поздравляю, вы только что разрешили мне войти в раздел ваших сверхзащищенных администраторов, указав ложное имя пользователя и ложный пароль. Серьезно, если вы мне не верите, создайте базу данных с помощью предоставленного мною кода и запустите этот PHP-код, который на первый взгляд действительно ДЕЙСТВИТЕЛЬНО проверяет имя пользователя и пароль.

Итак, в ответ, это то, почему вы кричали.

Итак, давайте посмотрим, что пошло не так, и почему я только что попал в вашу пещеру супер-админ-только-летучая мышь. Я сделал предположение и предположил, что вы не были осторожны со своими данными и просто передали их напрямую в базу данных. Я сконструировал вход таким образом, чтобы он ИЗМЕНИЛ запрос, который вы на самом деле выполняли. Итак, что это должно было быть, и чем это закончилось?

select id, userid, pass from users where userid='$user' and pass='$pass'

Это запрос, но когда мы заменяем переменные фактическими данными, которые мы использовали, мы получаем следующее:

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

Посмотрите, как я сконструировал свой «пароль», чтобы он сначала закрывал одинарную кавычку вокруг пароля, а затем вводил совершенно новое сравнение? Затем для безопасности я добавил еще одну «строку», чтобы одинарная кавычка закрывалась, как и ожидалось, в исходном коде.

Однако речь идет не о людях, которые кричат ​​на вас, а о том, как сделать ваш код более безопасным.

Итак, что пошло не так, и как мы можем это исправить?

Это классическая атака SQL-инъекций. Один из самых простых в этом отношении. По шкале векторов атаки это малыш атакует танк - и выигрывает.

Итак, как мы можем защитить ваш священный раздел администратора и сделать его красивым и безопасным? Первое, что нужно сделать, это прекратить использовать эти действительно старые и устаревшие mysql_* функции. Я знаю, что вы следовали учебному пособию, которое вы нашли в Интернете, и оно работает, но оно старое, оно устарело, и за несколько минут я только что преодолел его, не потратив ни капельки пота.

Теперь у вас есть лучшие варианты использования mysqli_ или PDO . Я лично большой поклонник PDO, поэтому я буду использовать PDO в оставшейся части этого ответа. Есть «за» и «против», но лично я считаю, что «за» намного перевешивают «против». Он переносим между несколькими ядрами баз данных - используете ли вы MySQL или Oracle или просто что-то кровавое - просто изменив строку подключения, он обладает всеми интересными функциями, которые мы хотим использовать, и он приятен и чист. Мне нравится чистый.

Теперь давайте снова посмотрим на этот код, на этот раз написанный с использованием объекта PDO:

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }
    $isAdmin=false;

    $database='prep';
    $pdo=new PDO ('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $sql="select id, userid, pass from users where userid=:user and pass=:password";
    $myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
    {
        while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
        {
            echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
            $isAdmin=true;
            // We have correctly matched the Username and Password
            // Lets give this person full access
        }
    }

    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

Основные отличия в том, что больше нет mysql_* функций. Все это делается через объект PDO, во-вторых, он использует подготовленный оператор. Теперь, какое предварительное утверждение вы спрашиваете? Это способ сообщить базе данных перед запуском запроса, какой запрос мы собираемся запустить. В этом случае мы говорим базе данных: «Привет, я собираюсь запустить оператор select, требующий идентификатора, идентификатора пользователя и передачи от пользователей таблицы, где идентификатор пользователя является переменной, а передача также является переменной».

Затем в операторе execute мы передаем базе данных массив со всеми переменными, которые он теперь ожидает.

Результаты фантастические. Давайте снова попробуем эти комбинации имени пользователя и пароля:

user: bob
pass: somePass

Пользователь не был подтвержден. Потрясающие.

Как насчет:

user: Fluffeh
pass: mypass

О, я просто немного взволнован, это сработало: проверка прошла. У нас есть проверенный админ!

Теперь, давайте попробуем данные, которые введет умный парень, чтобы попытаться обойти нашу маленькую систему проверки:

user: bob
pass: n' or 1=1 or 'm=m

На этот раз мы получаем следующее:

You could not be verified. Please try again...

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

Наконец, это не означает, что это ИДЕАЛЬНЫЙ код. Есть еще много вещей, которые вы можете сделать, чтобы улучшить его, например, использовать хешированные пароли, гарантировать, что при хранении конфиденциальной информации в базе данных вы не сохраняете ее в виде простого текста, имеете несколько уровней проверки - но на самом деле, если Вы просто измените свой старый подверженный инъекциям код на это, вы будете ХОРОШО на пути к написанию хорошего кода - и тот факт, что вы продвинулись так далеко и все еще читаете, дает мне чувство надежды, что вы не только реализуете этот тип кода при написании ваших веб-сайтов и приложений, но вы можете выйти и исследовать те другие вещи, которые я только что упомянул - и многое другое. Напишите лучший код, который вы можете, а не самый простой код, который едва работает.


Я считаю, что приведенные выше ответы действительно длинные, поэтому подведем итог:

Расширение mysqli имеет ряд преимуществ, ключевые улучшения по сравнению с расширением mysql:

  • Объектно-ориентированный интерфейс
  • Поддержка подготовленных заявлений
  • Поддержка нескольких заявлений
  • Поддержка транзакций
  • Расширенные возможности отладки
  • Поддержка встроенного сервера

Источник: MySQLi обзор

Как объяснено в ответах выше, альтернативами mysql являются mysqli и PDO (объекты данных PHP).

  • API поддерживает подготовленные операторы на стороне сервера: поддерживается MYSQLi и PDO
  • API поддерживает подготовленные операторы на стороне клиента: поддерживается только PDO
  • API поддерживает хранимые процедуры: MySQLi и PDO
  • API поддерживает множественные операторы и все функции MySQL 4.1+ - поддерживается MySQLi и в основном также PDO

И MySQLi, и PDO были введены в PHP 5.0, тогда как MySQL был представлен до PHP 3.0. Следует отметить, что MySQL включен в PHP5.x, хотя и не рекомендуется в более поздних версиях.


Расширение MySQL:

  • Не находится в стадии активной разработки
  • Официально deprecated PHP 5.5 (выпущена в июне 2013 г.).
  • Полностью removed с PHP 7.0 (выпущено в декабре 2015 г.)
    • Это означает, что по состоянию на 31 декабря 2018 года он не будет существовать ни в одной поддерживаемой версии PHP. В настоящее время он получает только обновления безопасности .
  • Отсутствует интерфейс OO
  • Не поддерживает:
    • Неблокирующие, асинхронные запросы
    • Подготовленные операторы или параметризованные запросы
    • Хранимые процедуры
    • Несколько заявлений
    • операции
    • «Новый» метод аутентификации по паролю (включен по умолчанию в MySQL 5.6; требуется в 5.7)
    • Все функциональные возможности в MySQL 5.1

Поскольку он устарел, его использование делает ваш код менее надежным в будущем.

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

Смотрите сравнение расширений SQL .


Сначала давайте начнем со стандартного комментария, который мы даем всем:

share . Они больше не поддерживаются deprecated . Видишь красную коробку ? Вместо этого узнайте о готовых утверждениях и используйте PDO или MySQLi - эта статья поможет вам решить, какие именно. Если вы выбираете PDO, вот хороший урок .

Давайте рассмотрим это, предложение за предложением, и объясним:

  • Они больше не поддерживаются и официально устарели

    Это означает, что сообщество PHP постепенно отказывается от поддержки этих очень старых функций. Они, вероятно, не существуют в будущей (недавней) версии PHP! Дальнейшее использование этих функций может нарушить ваш код в (не очень) будущем.

    NEW! - ext / mysql deprecated

    Новее! ext / mysql был удален в PHP 7 .

  • Вместо этого вы должны узнать о готовых утверждениях

    mysql_* не поддерживает подготовленные операторы , что (среди прочего) является очень эффективной контрмерой против SQL-инъекции . Он исправил очень серьезную уязвимость в MySQL-зависимых приложениях, которая позволяет злоумышленникам получить доступ к вашему сценарию и выполнить любой возможный запрос к вашей базе данных.

    Для получения дополнительной информации см. Как я могу предотвратить внедрение SQL в PHP?

  • Видишь красную коробку?

    Когда вы переходите на любую страницу руководства по функциям mysql , вы видите красное поле, объясняющее, что его больше не следует использовать.

  • Используйте либо PDO, либо MySQLi

    Существуют лучшие, более надежные и хорошо построенные альтернативы: PDO , который предлагает полный подход ООП к взаимодействию с базой данных, и MySQLi , который является специфическим улучшением для MySQL.





database