MySQL en Slackware con seguridad desde el inicio

Este documento es una aportación de Jorge Armando Medina, y se forma parte de la página slackware linux.

INTRODUCCIÓN

MySQL es actualmente el sistema de administración de bases de datos SQL mas popular en el Open Source, ya que es ampliamente utilizado en los desarrollos web gracias a su rapidez, estabilidad y a su integración con otros lenguajes de scripting como por ejemplo PHP.

En este documento se pretende dar una introducción básica a su instalación y configuración inicial en sistemas GNU/Linux, esto no quiere decir que es una guia avanzada para su configuración, con el tiempo este documento se ira extendiendo en capítulos mas avanzados.

Ya que MySQL es actualmente distribuido por la mayoría de distribuciones Linux podrás instalarlo desde los paquetes binarios de tu distribución preferida, en este documento se trabajara sobre la distribución Slackware 10.1, para otras distribuciones ver el apéndice que sera agregado próximamente, es recomendable utilizarla version mas actualizada de los paquetes para no estar vulnerables a bugs o otro tipo de fallas.

Informacion sobre el prompt

Cuando vean el símbolo "#" al inicio de el prompt, por ejemplo:

# installpkg mysql-4.0.20-i486-1.tgz

Significa que el comando debe de ser ejecutado como el usuario administrador de el sistema en los unix/linux, es el usuario root.

Cuando vea el símbolo "$" al inicio de el prompt, por ejemplo:

$ ls -l /var/log/packages/ | grep mysql

Significa que el comando debe de ser ejecutado como un usuario ordinario, esto se hace asi ya que hay comandos que no requieren privilegios especiales para ser ejecutados, o tienen que ser ejecutados como un usuario en especifico, como en unos ejemplos siguientes se tienen que hacer con el usuario mysql.

NOTA: En Slackware en programa servidor y el cliente vienen en el mismo paquete: mysql-4.0.23a-i486-1.tgz

Comprobación

Lo primero sera comprobar si nuestro sistema ya tiene instalados los paquetes de MySQL, así:

$ ls -l /var/log/packages/ | grep mysql
-rw-r--r--  1 root root  14341 2005-02-12 20:12 mysql-4.0.23a-i486-1

Lo cual nos debió de mostrar algo asi si es que ya esta instalado.

En este caso los paquetes ya estan instalados, si en tu caso no los tienes instalados es recomendable ver si existen paquetes mas nuevos en en algunos de los servidores de Slackware, si no es así, deberas instalarlos desde tus CD's de instalación, podría ser asi:

# cd /mnt/cdrom/slackware/ap
# installpkg mysql-4.0.20-i486-1.tgz

o bajarlo directo de el FTP:

# wget 
ftp://ftp.slackware.com/pub/slackware/slackware-10.1/slackware/ap/mysql-4.0. 2 3
a - i486-1.tgz

Si existieran nuevos paquetes y dispones de conexión a Internet podrás hacer uso del paquete swaret para bajar estos paquetes e instalarlos, asi:

# swaret update

y despues:

# swaret --install mysql

Si todo completo satisfactoriamente ya tendremos instalado MySQL en nuestro sistema.

Inicialización del Servidor (servicio) mysqld

Antes de poder iniciar el servicio de mysql tendremos que tener una base de datos, para instalar una base de datos inicial se deberá de hacer esto como root:

# su - mysql
$ mysql_install_db

NOTA: Lo que hicimos aquí fue convertirnos en el usuario "mysql", es muy importante hacer esto antes de hacer algun cambio a la base de datos, o el servicio mysqld no podrá escribir en ella despues, (lo cual puede ser arreglado con: 'chown -R mysql.mysql /var/lib/mysql'). Este procedimiento es el que viene explicado en la guia de referencia oficial de MySQL, y viene explicado en el script /etc/rc.d/rc.mysqld.

Esto es lo que sucede cuando se ejecuta el comando anterior:

$ mysql_install_db
Preparing db table
Preparing host table
Preparing user table
Preparing func table
Preparing tables_priv table
Preparing columns_priv table
Installing all prepared tables
050418 22:23:27 /usr/libexec/mysqld: Shutdown Complete


To start mysqld at boot time you have to copy support-files/mysql.server
to the right place for your system

PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:
/usr/bin/mysqladmin -u root password 'new-password'
/usr/bin/mysqladmin -u root -h jamedina password 'new-password'
See the manual for more instructions.

You can start the MySQL daemon with:
cd /usr ; /usr/bin/mysqld_safe &

You can test the MySQL daemon with the benchmarks in the 'sql-bench' directory:
cd sql-bench ; perl run-all-tests

Please report any problems with the /usr/bin/mysqlbug script!

The latest information about MySQL is available on the web at
http://www.mysql.com
Support MySQL by buying support/licenses at https://order.mysql.com

$

NOTA: Hay que revisar antes que nada que el script puso los permisos correctos para /var/lib/mysql deberían de quedar asi:

$ ls -ld /var/lib/mysql
drwxr-x---  4 mysql mysql 96 2005-04-18 22:23 /var/lib/mysql/

Si no quedo asi, regresa y revisa los pasos.


Bien ahora que ya tenemos instalado el paquete necesario y tenemos las bases de datos creadas entonces tendremos que iniciar el servidor para empezar a trabajar con el, para iniciarlo en Slackware es del siguiente modo:

Dar permisos de ejecución a /etc/rc.d/rc.mysqld asi

# chmod +x /etc/rc.d/rc.mysqld

Lo comprobamos asi:

# v /etc/rc.d/rc.mysqld
-rwxr-xr-x  1 root root 2260 2005-01-25 19:47 /etc/rc.d/rc.mysqld*

Ahora si podrá ser iniciado el servicio mysqld asi:

# /etc/rc.d/rc.mysqld start
# Starting mysqld daemon with databases from /var/lib/mysql

NOTA: Probablemente despues de ejecutar el comando anterior no te regrese al prompt, si no fue asi solo hay que teclear Enter para regresar al prompt del shell.

COMPROBACIÓN INICIAL

Primero que nada comprobaremos que el servicio esta corriendo en el sistema:

$ /usr/bin/mysqladmin version
/usr/bin/mysqladmin  Ver 8.40 Distrib 4.0.23a, for slackware-linux-gnu on i486
Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL license

Server version          4.0.23a
Protocol version        10
Connection              Localhost via UNIX socket
UNIX socket             /var/run/mysql/mysql.sock
Uptime:                 2 min 10 sec

Threads: 1  Questions: 1  Slow queries: 0  Opens: 6  Flush tables: 1  Open
tables: 0  Queries per second avg: 0.008

$

También puedes hacer una comprobación con el siguiente comando:

$ /usr/bin/mysqladmin variables

Lo cual nos debería regresar una gran salida mostrandonos las variables de entorno del servidor MySQL.

Ahora verificaremos que podemos apagar el servicio mysqld:

$ /usr/bin/mysqladmin -u root shutdown
jmedina@jamedina:~$ STOPPING server from pid file /var/run/mysql/mysql.pid
050418 22:31:33  mysqld ended

NOTA: Probablemente despues de ejecutar el comando anterior no te regrese al prompt, si no fue asi solo hay que teclear Enter para regresar al prompt del shell.

Aunque esta no es la manera adecuada para apagar el servicio mysqld, deberemos de usar el script de Slackware para apagarlo, de esta manera:

# /etc/rc.d/rc.mysqld stop

Ahora tendremos que comprobar que podemos volver a iniciar el servicio mysqld:

# /etc/rc.d/rc.mysqld start

Ahora haremos otro test para verificar que el servicio esta trabajando usando el comando mysqlshow asi:

$ mysqlshow
+-----------+
| Databases |
+-----------+
| mysql     |
| test      |
+-----------+
$

El cual nos dice que tiene las bases de datos "mysql" y "test".

# mysqlshow mysql
Database: mysql
+--------------+
|    Tables    |
+--------------+
| columns_priv |
| db           |
| func         |
| host         |
| tables_priv  |
| user         |
+--------------+
#

Este comando solo podrá ser ejecutado como root (note el "#" en el prompt) y nos mostrara las tablas de la base de datos "mysql".

Hasta ahora sabemos que tenemos correctamente instalado y trabajando nuestro servicio mysqld, lo que sigue es empezar con las configuraciones previas.

CONFIGURACIÓN INICIAL DE SEGURIDAD

Primero que nada eliminaremos la base de datos de ejemplo "test" y todas las cuentas excepto la cuenta local "root".

Nos conectamos al servidor de bases de datos asi:

$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4 to server version: 4.0.23a

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

mysql>

Lo cual nos pondrá en el prompt de mysql (este es el cliente):

mysql>

y ahora ejecutaremos:

mysql> drop database test;
Query OK, 0 rows affected (0.02 sec)

mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> delete from db;
Query OK, 2 rows affected (0.02 sec)

Y refrescamos los privilegios:

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

Y salimos del CLI (Command line Interface) de mysql asi:

mysql> quit
Bye

o

mysql> \q
Bye

Y seguimos con la configuración de seguridad.

De manera predeterminada MySQL permite a cualquier usuario en el host local (localhost) entrar al CLI y ejecutar consultas, claro no a la base de datos "mysql" ya que solo el usuario "root" de MySQL puede hacer consultas a esa base de datos, lo que sigue es prevenir que cualquier usuario en el host local pueda entrar al CLI sin contraseña. Un usuario normal puede entrar al CLI de la siguiente manera:

$ mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7 to server version: 4.0.23a

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

mysql>

De esta manera podrás acceder al CLI sin una contraseña y estaras en el prompt de MySQL.

Para prevenir esto entraremos como usuario "root" al CLI asi:

$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8 to server version: 4.0.23a

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

mysql>

Usaremos la base de datos "mysql" la cual es la que almacena los privilegios y configuración de acceso con el siguiente comando:

mysql> use mysql;                # el signo ";" es opcional con el comando "use".
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
 
Database changed
mysql>

De esta manera podremos trabajar con la base de datos "mysql".

Ahora haremos una consulta para ver los privilegios de acceso a mysqld:

mysql> SELECT host,user,password FROM user;
+-----------+------+----------+
| host      | user | password |
+-----------+------+----------+
| localhost | root |          |
| jamedina  | root |          |
| localhost |      |          |
| jamedina  |      |          |
+-----------+------+----------+
4 rows in set (0.00 sec)

mysql>

Esto nos muestra que el usuario root puede acceder desde el localhost y jamedina (este es el nombre del host) sin contraseña alguna, también nos muestra que cualquier usuario desde el localhost puede entrar al CLI sin contraseña. Para prevenir esto usaremos este comando.

mysql> DELETE FROM user WHERE NOT (host="localhost" AND user="root");
Query OK, 3 rows affected (0.02 sec)
 
mysql>

Ahora vemos nuevamente los privilegios:

mysql> SELECT host,user,password FROM user;
+-----------+------+----------+
| host      | user | password |
+-----------+------+----------+
| localhost | root |          |
+-----------+------+----------+
1 row in set (0.00 sec)

mysql>

Con esto vemos que ahora solo el usuario root puede acceder desde el localhost sin contraseña al CLI, lo cual también lo prevendremos mas adelante.

Ahora refrescaremos los privilegios para mysqld:

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql>

Y salimos del CLI con cualquiera de los dos comandos:

mysql> quit

o

mysql> \q

Ahora comprobaremos que un usuario normal puede acceder al CLI sin contraseña (claro solo desde el localhost):

$ mysql
ERROR 1045: Access denied for user: 'jmedina@localhost' (Using password: NO)
$

Hasta este momento ningún usuario normal podrá acceder al CLI sin contraseña, pero cualquier usuario normal podrá acceder identificándose como usuario "root" ante mysqld asi:

$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10 to server version: 4.0.23a

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

mysql>

Entonces tendremos que prevenir esto de la siguiente manera:

Tendremos que asignar una contraseña para el usuario "root" de MySQL (no el usuario de sistema Linux), como recomendación no uses una contraseña igual que la del administrador del sistema, se cuidadoso con la contraseña que asignes.

  • Método 1 (No recomendado)
    $ mysqladmin -u root password 'tu contraseña'
    $
  • Método 2 (Recomendado):
    $ mysql -u root
    mysql> SET PASSWORD FOR root@localhost=PASSWORD('tu contraseña');

Ahora que asignamos una contraseña al usuario root comprobaremos que ya no puede accesar sin la contraseña:

NOTA: No es una buena practica cambiar la contraseña desde la linea de comandos, por ejemplo, usando el comando "mysqladmin password". Esto es especialmente importante cuando trabajan otros usuarios en el servidor. En esos caso el password puede ser fácilmente revelado, por ejemplo, usando "ps -aux" o viendo los archivos del historial (~/,history, ~/.bash_history etc).

$ mysql -u root
ERROR 1045: Access denied for user: 'root@localhost' (Using password: NO)

Para poder acceder como usuario "root" al CLI haremos uso del parametro "-p" para usar validación por contraseña:

$mysql -u root -p
Enter password:

De esta manera solo podrás acceder como root con una contraseña:

Ahora comprobamos con esto:

mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
 
Database changed
mysql>

mysql> SELECT host,user,password FROM user;
+-----------+------+------------------+
| host      | user | password         |
+-----------+------+------------------+
| localhost | root | 565491d704013245 |
+-----------+------+------------------+
1 row in set (0.00 sec)

mysql>

Como podemos ver, el usuario "root" desde 'localhost' necesita contraseña (la cual se muestra cifrada) para acceder, lo cual es recomendable.

Nuevamente refrescamos los privilegios asi:

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

Y salimos:

mysql> \q
bye

Ahora ya esta restringido el acceso desde el localhost a cualquier usuario que se autentique sin contraseña, lo que sigue es saber como cambiar (actualizar) el registro de la contraseña de "root" u otro usuario, este es el procedimiento:

  • Desde el shell (No recomendado):
    $ mysqladmin -u root -p password 'nuevo password'
    Enter password:    <---- Aquí Ingresar la contraseña anterior.
  • Desde el CLI de mysql (Recomendado):
    mysql> use mysql;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    
    mysql> UPDATE user SET Password=PASSWORD('password') WHERE user='root';
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql>
    
    mysql> FLUSH PRIVILEGES;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql>
    
    mysql> quit
    bye

Ahora mencionare una medida mas de seguridad la cual también es recomendable y consiste en cambiar el nombre por default de la cuanta administrador de mysql (root), a algun nombre diferente que pueda ser mas difícil de adivinar. Este cambio hará mas difícil utilizar un ataque de fuerza bruta o con diccionario a la cuenta de administrador. En tal caso el intruso tendrá que adivinar el password, pero primero el nombre de la cuenta de administrador, esto se hace asi:

mysql> use mysql;
mysql> update user set user="mydbadmin" where user="root";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
mysql> quit

Ahora como ultimo test apagaremos el servicio mysqld asi:

# /etc/rc.d/rc.mysqld stop

Y comprobaremos que lo podamos reiniciar con:

# /etc/rc.d/rc.mysqld start

Bien, ahora nuestro servidor MySQL ya esta correctamente instalado y configurado con las medidas de seguridad apropiadas.

Finalmente debemos de eliminar el contenido del historial de MySQL (~/.mysql_history), en el cual todos los comandos SQL ejecutados han sido almacenados (especialmente passowrds, los cuales son almacenados en texto plano).

$ cat /dev/null > ~/.mysql_history

NOTA: Como podemos ver en el comando anterior, fue ejecutado como usuario normal, ya que las tareas de cambiar contraseñas fueron hechas con un usuario normal.

NOTA: este procedimiento deberá de ser aplicado para todas las cuentas con las que se ha estado trabajando (si es que si hicieron las pruebas con un usuario normal y con el usuario root del sistema).

NOTA ULTIMA

Para deshabilitar las conexiones externas al servidor de bases de datos (si no las necesitas, esto es recomendable para incrementar la seguridad) entonces hay que descomentar la linea:

#SKIP="--skip-networking" 

en el script "/etc/rc.d/rc.mysqld" ya que de manera predeterminada mysqld abre un socket TCP/IP para trabajar en red, puede comprobarse corriendo el comando:

# netstat -plutn | grep mysql
tcp   0   0 0.0.0.0:3306   0.0.0.0:*   LISTEN   2010/mysqld

Despues que se descomente la linea anteriormente mencionada se deberá de reiniciar reiniciar el servicio mysqld (/etc/rc.d/rc.mysql restart) de esta manera no abrira el socket TCP/IP y si se utiliza PHP solo trabajara con el socket unix lo cual es muy recomendable.

RESUMEN

Siguiendo el método descrito en este documento podremos tener un servidor MySQL funcional y si se siguieron las medidas de seguridad se tendrá un servidor relativamente seguro, ya que al no escuchar en el puerto 3306/tcp y al aplicar contraseñas seguras podremos reducir el intento de ataques a los cuales se es vulnerable en una instalación por defualt.

Aunque este método no es 100% seguro asi podemos tener un servidor seguro para los usuarios malintencionados.

Si olvidaste la contraseña de el usuario "root" de MySQL, podrás recuperarlo siguiendo el procedimiento descrito en: http://dev.mysql.com/doc/mysql/en/resetting-permissions.html.

FIN.