База данных PHP / SQL запрашивает хорошую практику и безопасность - PullRequest
7 голосов
/ 06 мая 2009

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

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

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

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

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

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

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

Ответы [ 6 ]

9 голосов
/ 06 мая 2009

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

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

  1. Что касается атак с использованием SQL-инъекций, вы можете написать функцию, которая будет удалять общие операторы SQL из ввода, такие как «DROP» или «DELETE * WHERE», например:

    * $ sqlarray = array ("DROP", "or 1 = 1", "union select", "SELECT * FROM", "select host", "create table", "FROM users", "users WHERE" ); *

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

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

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

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

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

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

6 голосов
/ 06 мая 2009

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

  1. ditch 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 );

PROs:

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

Минусы:

  • Я не могу думать ни о чем.
3 голосов
/ 06 мая 2009

Я обычно не работаю с PHP, поэтому я не могу дать совет, специально предназначенный для ваших требований, но я предлагаю вам взглянуть на страницу OWASP, в частности, на отчет о 10 самых уязвимых местах:

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

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

2 голосов
/ 06 мая 2009

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

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

1 голос
/ 06 мая 2009

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

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

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


Пример с php.net

Пример # 3 Запрос "Best Practice"

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

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

   <?php
    if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_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($_POST['product_name']);
                $product_description = stripslashes($_POST['product_description']);
            } else {
                $product_name        = $_POST['product_name'];
                $product_description = $_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),
                        $_POST['user_id']);

            mysql_query($query, $link);

            if (mysql_affected_rows($link) > 0) {
                echo "Product inserted\n";
            }
        }
    } else {
        echo "Fill the form properly\n";
    }
0 голосов
/ 06 мая 2009

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

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