Хорошая практика и безопасность запросов к базе данных PHP / SQL

StackOverflow https://stackoverflow.com/questions/826981

Вопрос

Итак, я немного опытный php-разработчик и "занимаюсь этим чертовым делом" с 2007 года;тем не менее, я все еще относительно осторожен, когда дело доходит до защиты моих приложений.В том смысле, что я на самом деле не знаю всего, что мог бы и должен знать.

Я подобрал Защита веб-приложений PHP и я читаю свой путь через это, проверяя все на своем пути.У меня есть несколько вопросов к общей группе SO, которые касаются запросов к базе данных (в основном под управлением mysql):

При создании приложений, которые помещают данные в базу данных, достаточно ли mysql_real_escape_string и общей проверки (is_numeric и т.д.) Входных данных?Как насчет других типов атак, отличных от sql-инъекции?

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

Я работаю в среде, привязанной к php4, и php5 на данный момент не подходит.Был ли кто-нибудь еще в таком положении раньше, что вы сделали для защиты своих приложений, пока все крутые ребята используют этот замечательный новый интерфейс mysqli?

Каковы некоторые общие рекомендации, которые люди сочли полезными, с акцентом на создание инфраструктуры, способной выдерживать обновления и возможные миграции (например, перенос php4 на php5).

Примечание:проведя поиск, я не смог найти ничего похожего на это, что могло бы повлиять на безопасность php-mysql.

Это было полезно?

Решение

Мои рекомендации:

  1. откажитесь от mysqli в пользу PDO (с драйвером mysql)
  2. используйте PDO параметризованные подготовленные инструкции

Затем вы можете сделать что-то вроде:

$pdo_obj = new PDO( 'mysql:server=localhost; dbname=mydatabase', 
                    $dbusername, $dbpassword );

$sql = 'SELECT column FROM table WHERE condition=:condition';
$params = array( ':condition' => 1 );

$statement = $pdo_obj->prepare( $sql, 
    array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
$statement->execute( $params );
$result = $statement->fetchAll( PDO::FETCH_ASSOC );

Плюсы:

  1. Больше никаких экранирований вручную, поскольку PDO делает все это за вас!
  2. Относительно легко внезапно переключить серверные части базы данных.

Минусы:

  • я не могу придумать ни одного.

Другие советы

Ответ Хавьера со ссылкой на owasp - хорошее начало.

Есть еще несколько вещей, которые вы можете сделать больше:

<Ол>
  • Что касается атак с использованием SQL-инъекций, вы можете написать функцию, которая будет удалять общие операторы SQL из входных данных, например " DROP " или " УДАЛИТЬ * ГДЕ " ;, например:

    * $ sqlarray = array ("DROP", "или 1 = 1", "union select", "SELECT * FROM", "select host", "create table", "" ОТ пользователей "," пользователи ГДЕ "); *

    Затем напишите функцию, которая будет проверять ваш ввод по этому массиву. Убедитесь, что какие-либо вещи внутри $ sqlarray не будут обычным вводом ваших пользователей. (Не забудьте использовать strtolower, спасибо, lou).

  • Я не уверен, работает ли memcache с PHP 4, но вы можете установить некоторую защиту от спама с помощью memcache, разрешив только определенный удаленный IP-доступ к странице process.php X раз за период Y .

  • Привилегии важны. Если вам нужны только привилегии на вставку (скажем, обработка заказа), вам следует войти в базу данных на странице процесса заказа с пользователем, у которого есть только вставка, и, возможно, выбрать привилегии. Это означает, что даже если SQL-инъекция прошла, они могли выполнять только запросы INSERT / SELECT, а не удалять или реструктурировать.

  • Поместите важные файлы обработки php в такой каталог, как / include. Затем запретите всем IP-адресам доступ к этому каталогу / include.

  • Поместите соленую MD5 с агентом пользователя + remoteip + вашу соль в сеанс пользователя и проверяйте при каждой загрузке страницы, что правильный MD5 находится в их cookie.

  • Запретить определенные заголовки ( http://www.owasp.org/index.php / Testing_for_HTTP_Methods_and_XST ). Запретить PUT (если вам не нужны загрузки файлов) / TRACE / CONNECT / DELETE заголовки.

  • Я обычно не работаю с PHP, поэтому не могу дать совет, специально предназначенный для ваших требований, но я предлагаю вам взглянуть на страницу OWASP, в частности, на отчет о 10 самых уязвимых местах: http://www.owasp.org/index.php/Top_10_2007

    На этой странице для каждой уязвимости вы получаете список действий, которые можно предпринять, чтобы избежать проблемы на разных платформах (.Net, Java, PHP и т. д.)

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

    AFAIK, PHP / mySQL обычно не имеет параметризованных запросов.

    Использование sprintf () с mysql_real_escape_string () должно работать очень хорошо. Если вы используете соответствующие строки формата для sprintf () (например, «% d» для целых чисел), вы должны быть в полной безопасности.

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

       <?php
        if (isset(

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['product_name']) && isset(

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['product_description']) && isset(

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['user_id'])) { // Connect $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password'); if(!is_resource($link)) { echo "Failed to connect to the server\n"; // ... log the error properly } else { // Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON. if(get_magic_quotes_gpc()) { $product_name = stripslashes(

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['product_name']); $product_description = stripslashes(

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['product_description']); } else { $product_name =

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['product_name']; $product_description =

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['product_description']; } // Make a safe query $query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)", mysql_real_escape_string($product_name, $link), mysql_real_escape_string($product_description, $link),

    Я могу ошибаться, но этого должно быть недостаточно, чтобы использовать mysql_real_escape_string по предоставленным пользователем данным?

    если только они не являются числами, в этом случае вы должны убедиться, что они на самом деле являются числами, используя, например, ctype_digit или is_numeric или sprintf (используя % d или % u для принудительного ввода числа)

    Также неплохо было бы иметь отдельного пользователя mysql для ваших php-скриптов, которые могут только SELECT, INSERT, UPDATE и DELETE ...

    <Ч>

    Пример с php.net

      

    Пример № 3 «Лучшая практика» запроса      

    Использование mysql_real_escape_string () вокруг каждой переменной предотвращает SQL-инъекцию. Этот пример демонстрирует «наилучшую практику» метод запроса базы данных, независимый от настройки Magic Quotes.      

    Теперь запрос будет выполняться правильно, и атаки с использованием SQL-инъекций не будут работать.

    <*>
    POST['user_id']); mysql_query($query, $link); if (mysql_affected_rows($link) > 0) { echo "Product inserted\n"; } } } else { echo "Fill the form properly\n"; }

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

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top