WedX - журнал о программировании и компьютерных науках

PHP mysql_real_escape_string() защищает имя базы данных?

Я знаю, что mysql_real_escape_string()
добавляет обратную косую черту к следующим символам: \x00, \n, \r, \, ', " и \x1a

Я знаю, как это защищает запрос от внедрения чего-то вроде переменной в предложении where. Но вот сценарий, в котором я не уверен:

$query = "SELECT * FROM $db WHERE 1";

Если $db берется из пользовательского ввода, то пользователь может вставить что-то вроде:
$db = 'RealDatabase WHERE 1; DELETE FROM RealDatabase WHERE 1; SELECT FROM RealDatabase';

Насколько я понимаю, mysql_real_escape_string() не повлияет на эту строку, сделав окончательный запрос: $query = "SELECT * FROM RealDatabase WHERE 1; DELETE FROM RealDatabase WHERE 1; SELECT FROM RealDatabase WHERE 1";

который удалит базу данных. Есть ли другой уровень защиты, о котором я не знаю?

07.01.2010

  • Почему вы все равно принимаете пользовательский ввод имени базы данных? 07.01.2010
  • Наш набор данных действительно большой, поэтому мы разделили его на сотню или около того таблиц. Переменная GET определяет, к какой таблице страница должна обращаться. 07.01.2010
  • Простым способом сделать это было бы сравнить значение этой переменной с набором допустимых значений из белого списка, например. if( ! in_array($_GET['table'], $allowed_tables) die('HAX!'). 07.01.2010
  • @Brian: Это звучит ненужно и представляет серьезную угрозу безопасности. Сколько у вас рядов? 07.01.2010
  • У нас 52 стола. Все они имеют 100 000 и 1 000 000 строк, и очень важно, чтобы выборочные запросы выполнялись быстро. 07.01.2010
  • Тем не менее, какая скорость связана с именами таблиц, передаваемыми пользователем. имена таблиц не меняются от пользователя к пользователю (хотя временные таблицы могут). Пожалуйста, приведите пример того, почему имя таблицы должно быть передано от пользователя. 07.01.2010
  • @DeveloperChris - динамические таблицы и имена полей встречаются чаще, чем вы думаете, в базах данных с большими подмножествами таблиц. Кроме того, имена таблиц могут очень легко меняться от пользователя к пользователю (сегментирование базы данных Google). Хотя лучше иметь внутренний поиск, чтобы сказать вам, какую таблицу использовать на основе входных параметров, то, что есть у Брайана, на самом деле является очень реальной проблемой. 07.01.2010
  • Возможно, но вы все еще спрашиваете о проблемах, позволяющих пользователю указать имя базы данных/таблицы. скажем, например, вы предоставляете SaaS и разрешаете своим пользователям передавать имя таблицы. вполне возможно, что пользователь может получить доступ к информации другого лица, просто указав неправильное имя. в этом случае я бы использовал таблицу поиска внутри самой базы данных. каждый пользователь затем имеет свой собственный список таблиц, созданных при создании пользователя. никогда бы я не дал такую ​​информацию ненадежному пользователю. 08.01.2010

Ответы:


1

Уровень защиты, который вы ищете, обеспечивается обратными кавычками:

"SELECT * FROM `$db` WHERE 1";

Обратные кавычки используются для определения идентификаторов, которые в противном случае могли бы быть неоднозначными. (т. е. зарезервированные слова MySQL), и если вы принимают пользовательский ввод или имеют столбцы или базы данных с переменными именами, вам обязательно следует использовать обратные кавычки, иначе я обещаю, что в будущем у вас возникнут проблемы. Например, что, если бы у вас была система, в которой временное имя поля было создано с помощью некоторого пользовательского ввода, только оказалось, что поле в конечном итоге было названо update?

"SELECT field1,field2,update FROM table;"

Это терпит неудачу с треском. Тем не мение:

"SELECT `field`,`field2`,`update` FROM table"

работает просто отлично. (На самом деле это реальный пример из системы, над которой я работал несколько лет назад, в которой была эта проблема).

Это решает вашу проблему с точки зрения ввода плохого SQL. Например, следующий запрос просто вернет ошибку «неизвестный столбец», где test; DROP TABLE test — внедренный код атаки:

"SELECT * FROM `test; DROP TABLE test`;"

Однако будьте осторожны: SQL-инъекция по-прежнему возможна с помощью обратных кавычек!

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

$db = str_replace('`','',$db);
$sql = "SELECT * FROM `$db` WHERE 1";

Я использую оболочку базы данных, которая имеет отдельные функции для очистки данных и идентификаторов базы данных, и это то, что делает последний :)

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

  • 2

    Вы действительно должны изучить привязку ваших SQL-запросов.

    Это защитит вас практически от всех SQL-инъекций. Это сводится к следующему:

    (взято с PHP.net)

    $stmt = mssql_init('NewUserRecord');
    
    // Bind the field names
    mssql_bind($stmt, '@username',  'Kalle',  SQLVARCHAR,  false,  false,  60);
    
    // Execute
    mssql_execute($stmt);
    

    И PHP поддерживает связанные запросы практически во всех базах данных. Да, и, конечно же, вы все равно должны дезинфицировать все входные и выходные данные (дисплей).

    Дополнительная информация: - https://php.net/manual/en/function.mssql-bind.php

    07.01.2010
  • Вы не можете использовать параметры запроса для имен таблиц или столбцов или ключевых слов SQL. 07.01.2010

  • 3

    Нет, mysql_real_escape_string здесь вам не поможет. Функция не является контекстно-зависимой (не может быть, потому что НЕ ИМЕЕТ никакого контекста), и это совсем другая модель угрозы.

    Вам нужно пойти и проверить, что таблица существует, не отправляя введенное пользователем имя таблицы непосредственно на сервер. Лучшее решение — использовать серверный массив/справочную таблицу, содержащую имена таблиц, которые им разрешено использовать. Если они попытаются использовать что-то, чего там нет, не позволяйте им.

    Если вам действительно нужны ВСЕ таблицы, то вы можете просто спросить у сервера "какие таблицы у вас есть?" и запустите его вывод (возможно, кешируя его в течение некоторого периода времени, чтобы каждый раз не запрашивать сервер) - но есть вероятность, что в конечном итоге у вас будет таблица, в которую вы не хотите копаться, и тогда вам нужно в любом случае использовать массив, так что просто сделайте это.

    07.01.2010
  • Я бы не согласился с этим решением. Вы просто добавляете накладные расходы и создаете ненужную корреляцию между вашим кодом и вашей базой данных. Каждый раз, когда вы добавляете таблицу, вам придется обновлять массив кода. Нет никаких причин, по которым вы не можете попробовать выполнить запрос с динамическими именами таблиц/полей, и если запрос завершится ошибкой, вы просто поймаете ошибку и вернете сообщение. 07.01.2010

  • 4

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

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

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

    07.01.2010
  • Первоначально я сказал, что вы должны убедиться, что все имена баз данных являются чисто текстовыми и не содержат ; но оказывается, что имена баз данных и таблиц могут иметь ; символ в их имени. 07.01.2010

  • 5

    Поскольку в именах таблиц не используются пробельные символы, просто удалите их. Это сделало бы указанный выше $DB RealDatabaseWHERE1;DELETEFROMRealDatabase..... Это сделало бы запрос недействительным, но предотвратило бы ошибку.

    Если вы хотите предотвратить подобные «хакерские» вещи, просто выполните explode(' ', $db), а затем получите массив результатов [0]. Вот бы получить первую часть (RealDatabase) и ничего больше.

    07.01.2010
  • Вы уверены, что MySQL не принимает пробелы в именах таблиц? Я успешно использовал их в прошлом. 07.01.2010

  • 6

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

    07.01.2010
  • Я знаю, что экранирование всех запросов является хорошей практикой, но будет ли экранирования достаточным для предотвращения атаки в сценарии, который я составил? 07.01.2010

  • 7

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

    $realname = '';
    switch ($_GET['dbname']){
        case 'sometoken' : $realname = 'real_name'; break;
        case 'sometoken1' : $realname = 'real_name1'; break;
        case 'sometoken2' : $realname = 'real_name2'; break;
        case 'sometoken3' : $realname = 'real_name3'; break;
        case 'sometoken4' : $realname = 'real_name4'; break;
        case default : die ('Cheeky!!!');
    }
    
    $query = "SELECT * FROM `{$realname}` WHERE 1";
    

    или как вариант...

    $realname = $tablenames[$_GET['dbname']];
    
    if (!$realname)
        die ('Cheeky!!!');
    

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

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

    Убедитесь, что вы сначала проверили содержимое $_GET['dbname'], чтобы убедиться, что оно действительно, иначе будут выданы предупреждения.

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

    Безопасность слишком важна, чтобы позволить лени править.

    07.01.2010
  • Здесь тот же комментарий, что и к ответу Майкла Мэдсена. Вы создаете ненужную связь между вашим кодом и вашей базой данных, и с помощью этого метода вы не можете обновить одно без другого. Пока вы выполняете правильное экранирование, нет причин, по которым вы не можете попробовать выполнить запрос с динамическими именами таблиц/полей, и если запрос завершится ошибкой, вы просто поймаете ошибку и вернете сообщение. Очевидно, что подготовленные запросы лучше подходят для этого, но нет никаких причин, по которым вы не можете сделать это и с помощью обычного драйвера MySQL. 07.01.2010
  • ненужная связь между кодом и базой данных? За исключением хранимых процедур (неприменимо в этом случае), каждый раз, когда вы изменяете свою базу данных, вы должны изменять свой код. Вы понимаете, что ОП хотел получить имена своих таблиц от пользователя. В лучшем случае очень рискованный шаг. Подготовленные запросы не работают ни с именами динамических таблиц, ни с хранимыми процедурами. Мой ответ состоял в том, чтобы удовлетворить требования ОП И обеспечить некоторую безопасность. Ваш комментарий не имеет отношения к моему ответу, как и к ответу Майкла. 08.01.2010
  • Просто исправление моего комментария выше. Вы можете сделать это в хранимой процедуре, построив строку запроса в хранимой процедуре, но вы вернулись к исходной точке, вам все равно нужно избежать ввода пользователя, иначе инъекции sql все еще будут возможны . 09.01.2010
  • Нефильтрованный доступ @zombat к произвольным полям может вызвать проблемы. Скажем, у вас есть список сотрудников, а порядок динамический. Используется пользовательским интерфейсом для упорядочения по имени, фамилии или должности. Но с модификацией параметра можно упорядочить по зарплате, чего вы можете не хотеть, чтобы люди знали, кому платят больше и меньше. 07.07.2017
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]