Статьи Защищаем MySql. Шаг за шагом

Discussion in 'Статьи' started by k00p3r, 13 Jun 2005.

  1. k00p3r

    k00p3r Banned

    Joined:
    31 May 2005
    Messages:
    430
    Likes Received:
    8
    Reputations:
    2
    1. Введение

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

    Эта статья описывает основные шаги, выполнение которых, максимально защитит базу данных MySQL от локальных и удаленных нападений. Это третья и последняя статья из цикла статей, посвященных защите Apache, PHP и MySQL.

    1.1 Функциональные возможности

    В этой статье мы предполагаем, что Web-сервер Apache вместе с PHP модулем, был установлен в соответствии с требованиями предыдущих статей, и помещен в каталог /chroot/httpd.

    Кроме этого мы также принимаем следующее:
    База данных MySQL будет использоваться только PHP приложениями, установленными на том же самом хосте;
    Для управления базой данных будут использоваться стандартные административные средства, типа mysqladmin, mysql, mysqldump и т.д.;
    Для удаленного резервирования MySQL данных будет использоваться SSH протокол.

    1.2 Необходимые условия для защиты

    Чтобы достигнуть самого высокого возможного уровня защиты, установка и конфигурация mysql должна быть выполнена в соответствии со следующими требованиями:
    база данных mysql должна быть выполнена в chrooted среде;
    процессы mysql должны выполняться под уникальным UID/GID, неиспользуемым никаким другим системным процессом;
    Должен быть разрешен только локальный доступ к mysql;
    Основная учетная запись mysql должна быть защищена “сложным” паролем;
    Будет переименована учетная запись администратора;
    Должен быть заблокирован анонимный доступ к базе данных (используя учетную запись nobody);
    Должны быть удалены все типовые базы данных и таблицы.

    2. Установка MySQL

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

    pw groupadd mysql

    pw useradd mysql-c " mysql Сервер "-d/dev/null-g mysql-s/sbin/nologin

    2.1 Компиляция mysql

    Мы скомпилируем и установим mysql в каталог /usr/local/mysql:

    ./configure --prefix=/usr/local/mysql --with-mysqld-user=mysql --with-unix-socket-path=/tmp/mysql.sock --with-mysqld-ldflags=-all-static
    make
    su
    make install
    strip /usr/local/mysql/libexec/mysqld
    scripts/mysql_install_db
    chown -R root /usr/local/mysql
    chown -R mysql /usr/local/mysql/var
    chgrp -R mysql /usr/local/mysql

    Приведенный процесс установки сервера практически идентичен описанному в руководстве к mysql. Единственным отличием является использование нескольких дополнительных параметров, указанных в строке: ./configure. Наиболее важным отличием является использование параметра -- with-mysqld-ldflags =-all-static, который делает MySQL сервер статически связанным. Это значительно упрощает процесс chrooting сервера, как описано в Разделе 3. Остальные параметры приказывают make программе установить программное обеспечение в каталог /usr/local/mysql, выполнить MySQL демон с привилегиями учетной записи mysql, и создать сокет mysql.sock в каталоге /tmp.

    2.2 Копирование файлов конфигурации

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

    cp support-files/my-medium.cnf /etc/my.cnf
    chown root:sys /etc/my.cnf
    chmod 644 /etc/my.cnf

    2.3 Запуск сервера

    Теперь mysql полностью установлен и готов к выполнению. Мы можем запустить mysql сервер, выполнив следующую команду:

    /usr/local/mysql/bin/mysqld_safe

    2.4 Проверка подключений

    Попробуйте установить связь с базой данных следующим образом:

    /usr/local/mysql/bin/mysql -u root mysql

    Welcome to the MySQL monitor. Commands end with ; or \g.

    Your MySQL connection id is 2 to server version: 4.0.13-log

    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

    mysql> show databases;

    +----------+

    | Database |

    +----------+

    | mysql |

    | test |

    +----------+

    2 rows in set (0.00 sec)

    mysql> quit;

    Как только подключение успешно установлено, мы можем остановить работу базы данных:

    /usr/local/mysql/bin/mysqladmin -u root shutdown

    и начать защиту программного обеспечения. Иначе, мы должны будем проанализировать информацию, сохраненную в файле регистрации /usr/local/mysql/var/`hostname`.err, и устранить причину проблемы.

    3. Chrooting сервер

    Первый шаг защиты mysql должен подготовить chrooted среду, в которой будет выполняться mysql сервер. Chrooting методика была подробно описана в первой статье этого цикла ("Защита Apache: Шаг за шагом, поэтому если Вы не знакомы с этой методикой или не знаете почему рекомендуется chrooting, пожалуйста прочтите эту статью.

    3.1 Операционная система

    Как и в предыдущих статьях, мы будем основываться на операционной системе FreeBSD 4.7. Однако представленные методы должны также применяться и на более современных unix и unix-подобных системах.

    3.2 Подготовка chroot среды

    Чтобы подготовить chrooted среду, мы должны создать следующую структуру каталога:

    mkdir -p /chroot/mysql/dev
    mkdir -p /chroot/mysql/etc
    mkdir -p /chroot/mysql/tmp
    mkdir -p /chroot/mysql/var/tmp
    mkdir -p /chroot/mysql/usr/local/mysql/libexec
    mkdir -p /chroot/mysql/usr/local/mysql/share/mysql/english

    3.3 Установка прав доступа

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

    chown -R root:sys /chroot/mysql
    chmod -R 755 /chroot/mysql
    chmod 1777 /chroot/mysql/tmp



    3.4 Создание структуры каталогов

    Затем, необходимо скопировать следующие файлы в новую структуру каталога:

    cp/usr/local/mysql/libexec/mysqld/chroot/mysql/usr/local/mysql/libexec/

    cp/usr/local/mysql/share/mysql/english/er rmsg.sys/chroot/mysql/usr/local/mysql/share/mys ql/english/

    cp/etc/hosts/chroot/mysql/etc/

    cp/etc/host.conf/chroot/mysql/etc/

    cp/etc/resolv.conf/chroot/mysql/etc/

    cp/etc/group/chroot/mysql/etc/

    cp/etc/master.passwd/chroot/mysql/etc/passwords

    cp/etc/my.cnf/chroot/mysql/etc/

    3.5 Сжатие паролей и групп

    Из файлов: /chroot/mysql/etc/passwords и /chroot/mysql/etc/group мы должны удалить все строки кроме учетной записи mysql и группы. Затем, мы должны, создать базу данных паролей (допустимо только в FreeBSD):

    cd /chroot/mysql/etc
    pwd_mkdb -d /chroot/mysql/etc passwords
    rm -rf /chroot/mysql/etc/master.passwd



    3.6 Специальные соображения

    Как и в случае с Web-сервером Apache, мы должны создать специальный файл устройства /dev/null:

    ls -al /dev/null

    crw-rw-rw- 1 root sys 2, 2 Jun 21 18:31 /dev/null

    mknod /chroot/mysql/dev/null c 2 2

    chown root:sys /chroot/mysql/dev/null

    chmod 666 /chroot/mysql/dev/null

    Теперь необходимо скопировать базу данных mysql, которая содержит таблицы, созданные в процессе инсталляции mysql:

    cp-R/usr/local/mysql/var//chroot/mysql/usr/local/mysql/var

    chown-R mysql:mysql/chroot/mysql/usr/local/mysql/var

    3.7 Локализация

    Если будет использоваться какой-либо язык кроме английского, то необходимо будет скопировать нужный набор символов из каталога /usr/local/mysql/share/mysql/charsets.

    3.8 Проверка конфигурации

    Теперь MySQL готов к запуску в chrooted среде. Мы можем проверить, правильно ли запускается MySql, выполнив следующую команду:

    chrootuid /chroot/mysql mysql /usr/local/mysql/libexec/mysqld &

    Если произойдет какая-либо ошибка, то необходимо будет использовать команду truss или подобную ей, типа ktrace/kdump, strace, и т.д. Это поможет нам определить и устранить причину проблемы.

    Заметьте, что для выполнения процесса mysqld, вместо chroot, как в случае Apache или PHP, использовалась программа chrootuid. Главное отличие состоит в том, что chrootuid меняет владельца запущенного процесса. В нашем примере, mysqld выполняется в chrooted среде, но владелец процесса - не root, а пользователь mysql. Chrootuid во многих операционных системах не установлен по умолчанию, поэтому необходимо загрузить и установить эту программу вручную. Программа Chrootuid может быть загружена здесь .

    4. Конфигурирование сервера

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

    В случае заданной по умолчанию инсталляции mysql, главным файлом конфигурации является /etc/my.cnf. Однако, в нашем случае, из-за выполнения сервера в chrooted среде, мы будем использовать два файла конфигурации: /chroot/mysql/etc/my.cnf и /etc/my.cnf. Первый будет использоваться сервером mysql, а второй - утилитами mysql (например: mysqladmin, mysql, mysqldump и т.д.). В обоих случаях, потребуются некоторые изменения конфигурации.

    4.1 Отключение удаленного доступа

    Первое изменение касается порта 3306/tcp, который mysql прослушивает по умолчанию. Поскольку, согласно начальным предположениям по защите, база данных будет использоваться только локально установленными PHP приложениями, мы можем свободно отключить прослушивание этого порта. Это ограничит возможность нападения на базу данных mysql прямыми TCP/IP подключениями с других хостов. Чтобы отключить прослушивание упомянутого порта, необходимо к разделу [mysqld] файла /chroot/mysql/etc/my.cnf добавить следующий параметр:

    skip-networking

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

    backuphost$ ssh mysqlserver /usr/local/mysql/bin/mysqldump -A > backup

    4.2 Улучшение локальной защиты

    Следующее изменение должно отключить использование команды LOAD DATA LOCAL INFILE, что поможет предотвратить несанкционированное чтение данных из локальных файлов. Это имеет особенное значение, в случае если в PHP будет найдена новая уязвимость к SQL инъекциям.

    Для этой цели, в раздел [mysqld] файла /chroot/mysql/etc/my.cnf, необходимо добавить следующий параметр:

    Set-variable=local-infile=0

    Кроме того, чтобы сделать более удобным использование административных средств базы данных, в разделе [Client] файла /etc/my.cnf, должен быть изменен следующий параметр:

    socket = /chroot/mysql/tmp/mysql.sock

    Благодаря этому, каждый раз при выполнении этих утилит, не будет никакой потребности передавать в команды: mysql, mysqladmin, mysqldump и т.д., параметр socket =/chroot/mysql/tmp/mysql.sock.

    4.3 Изменение пароля администратора

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

    chrootuid /chroot/mysql mysql /usr/local/mysql/libexec/mysqld &

    и изменить пароль администратора следующим образом:

    /usr/local/mysql/bin/mysql -u root

    mysql> SET PASSWORD FOR root@localhost=PASSWORD('new_password');

    Хорошей привычкой является отказ от изменений паролей из командной строки, например, используя команду "mysqladmin password". Это особенно важно, если на сервере работают несколько пользователей. В таком случае пароль можно легко узнать, например, используя команду "ps aux" или просмотрев файлы истории команд (~/.history, ~/.bash_history и т.д), в случае если на них установлены неподходящие права доступа.

    4.4 Удаление значений по умолчанию users/db

    Затем, мы должны удалить типовую базу данных (test) и все учетные записи, кроме главной локальной учетной записи:

    mysql> drop database test;

    mysql> use mysql;

    mysql> delete from db;

    mysql> delete from user where not (host="localhost" and user="root");

    mysql> flush privileges;

    Это предотвратит нашу базу данных от установления анонимных подключений, а также, независимо от параметра skip-networking в файле /chroot/mysql/etc/my.cnf --, удаленных подключений.

    4.5 Изменение имени учетной записи администратора.

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

    mysql> update user set user="mydbadmin" where user="root";
    mysql> flush privileges;

    4.6 Удаление файлов истории команд

    Наконец, мы должны удалить содержимое файла истории команд mysql (~/.mysql_history), в котором сохраняются все выполненные SQL команды (особенно пароли, сохраненные как открытый текст):

    5. Связь между PHP и mysql

    В предыдущей статье "Защищаем PHP: Шаг за шагом", автор упомянул о проблеме связи между PHP и mysql, в случае, если одна из этих программ выполняется в chrooted среде. Поскольку локально PHP связывается с mysql, используя сокет /tmp/mysql.sock, размещение PHP в chrooted среде, означает, что они не могут связываться друг с другом. Для решения этой проблемы, каждый раз, запуская mysql, мы должны создавать постоянную связь с PHP chrooted средой:

    ln /chroot/mysql/tmp/mysql.sock /chroot/httpd/tmp/

    Обратите внимание на то, что сокет /chroot/mysql/tmp/mysql.sock и каталог /chroot/httpd/tmp должны быть физически помещены в том же самой файловой системе. Иначе программы не смогут связываться друг с другом, т.к. постоянные связи не работают между различными файловыми системами.

    6. Финальные шаги

    Теперь мы уже можем создавать все базы данных и учетные записи, которые будут использоваться определенными PHP приложениями. Необходимо подчеркнуть, что эти учетные записи должны иметь права доступа только к базам данных, используемым PHP приложениями. В частности они не должны иметь никаких прав доступа к базе данных mysql, и ни никаким системным или административным привилегиям (FILE, GRANT, ALTER, SHOW DATABASE, RELOAD, SHUTDOWN, PROCESS, SUPER и т.д.).

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

    #!/bin/sh
    CHROOT_MYSQL=/chroot/mysql
    CHROOT_PHP=/chroot/httpd
    SOCKET=/tmp/mysql.sock
    MYSQLD=/usr/local/mysql/libexec/mysqld
    PIDFILE=/usr/local/mysql/var/`hostname`.pid
    CHROOTUID=/usr/local/sbin/chrootuid
    echo -n " mysql"
    case "$1" in
    start)
    rm -rf ${CHROOT_PHP}/${SOCKET}
    nohup ${CHROOTUID} ${CHROOT_MYSQL} mysql ${MYSQLD} >/dev/null 2>&1 &
    sleep 5 && ln ${CHROOT_MYSQL}/${SOCKET} ${CHROOT_PHP}/${SOCKET}
    ;;
    stop)
    kill `cat ${CHROOT_MYSQL}/${PIDFILE}`
    rm -rf ${CHROOT_MYSQL}/${SOCKET}
    ;;
    *)
    echo ""
    echo "Usage: `basename $0` {start|stop}" >&2
    exit 64
    ;;
    esac
    exit 0

    В случае с нашей системой FreeBSD, вышеупомянутый сценарий должен быть помещен в каталог /usr/local/etc/rc.d, под именем mysql.sh.

    6.1 Заключение

    Применение методов, описанных в данной статье, позволит нам значительно увеличить степень защиты mysql. Запуская базу данных в chrooted среде, отключая прослушивание 3306/tcp порта, и применяя "строгие" пароли к учетным записям пользователей, мы можем сделать базу данных неуязвимой ко многим видам нападений, которые были бы возможны с заданной по умолчанию инсталляцией.

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