PHP mysql_real_escape_string () защищает имя базы данных? - PullRequest
4 голосов
/ 07 января 2010

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

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

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

Если $ 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";

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

Ответы [ 7 ]

8 голосов
/ 07 января 2010

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

"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";

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

1 голос
/ 07 января 2010

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

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

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

1 голос
/ 07 января 2010

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

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

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

1 голос
/ 07 января 2010

Вы действительно должны изучить привязку ваших 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 есть поддержка связанных запросов практически для всех баз данных. Да, и, конечно, вы все равно должны очистить все входные и выходные данные (дисплей).

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

0 голосов
/ 07 января 2010

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

$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'], чтобы убедиться, что он действителен первым, в противном случае будут выданы предупреждения.

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

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

0 голосов
/ 07 января 2010

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

0 голосов
/ 07 января 2010

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

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

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