Mejores Prácticas para Reforzar las Configuraciones de Seguridad del Servidor MySQL

Refuerce MySQL con usuarios de mínimo privilegio, restricciones de host, TLS, configuraciones más seguras de my.cnf, parches y auditoría básica.

Mejores Prácticas para Reforzar las Configuraciones de Seguridad del Servidor MySQL

El refuerzo de MySQL comienza con una pregunta simple: ¿qué ganaría un atacante si se filtrara una contraseña de aplicación? Si la respuesta es "todas las bases de datos desde cualquier lugar", su servidor necesita usuarios más restrictivos, reglas de red y configuración.

Utilice estas prácticas para reducir el radio de explosión de un compromiso sin hacer que la administración diaria sea tediosa.

1. Gestión de Usuarios y Accesos: El Principio de Mínimo Privilegio

Una gestión de usuarios efectiva es fundamental para la seguridad de MySQL. Otorgar a los usuarios solo los permisos que absolutamente necesitan es primordial.

Crear Usuarios Específicos para Aplicaciones Específicas

Evite usar el usuario root para conexiones de aplicaciones. En su lugar, cree usuarios dedicados con permisos granulares.

CREATE USER 'my_app_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON `your_database`.* TO 'my_app_user'@'localhost';

Exigir Contraseñas Fuertes

Las contraseñas fuertes y únicas son su primera línea de defensa. Utilice el plugin de validación de contraseñas incorporado de MySQL si está disponible.

  • Complejidad: Mezcle mayúsculas, minúsculas, números y símbolos.
  • Longitud: Apunte a al menos 12-16 caracteres.
  • Unicidad: Nunca reutilice contraseñas.
  • Rotación: Implemente una política para cambios regulares de contraseñas.

Puede habilitar el componente validate_password (MySQL 8.0+) o plugin (MySQL 5.7+):

INSTALL COMPONENT 'file://component_validate_password';
-- O para versiones anteriores
INSTALL PLUGIN validate_password SONAME 'validate_password.so';

-- Configurar la política de fortaleza (ej., MEDIUM para 8+ caracteres, mezcla de mayúsculas/minúsculas, números, especiales)
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 12;

Eliminar Usuarios Predeterminados y No Utilizados

MySQL puede incluir cuentas administrativas e internas. Mantenga las cuentas de sistema requeridas como mysql.session y mysql.sys intactas, pero elimine las cuentas anónimas y cualquier cuenta humana o de aplicación que ya no use.

-- Para identificar usuarios anónimos:
SELECT user, host FROM mysql.user WHERE user = '';
-- Para eliminar un usuario anónimo (si se encuentra):
DROP USER ''@'localhost';

-- Para eliminar bases de datos de prueba (si existen):
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';
FLUSH PRIVILEGES;

Restringir el Acceso por Host

Limite las cuentas de usuario para que se conecten solo desde direcciones IP o nombres de host específicos. Evite usar % como comodín para el host a menos que sea absolutamente necesario y esté acompañado de otros controles de seguridad sólidos.

-- El usuario solo puede conectarse desde localhost
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'AnotherStrongPass!';

-- El usuario solo puede conectarse desde una dirección IP específica
CREATE USER 'backup_user'@'192.168.1.100' IDENTIFIED BY 'BackupPass!';

Ser Cauteloso con GRANT OPTION

La cláusula WITH GRANT OPTION permite a un usuario otorgar sus propios privilegios a otros usuarios. Esto puede ser un riesgo de seguridad significativo si se otorga a usuarios no confiables. Úselo con moderación y solo para cuentas administrativas que realmente necesiten esta capacidad.

-- Un usuario con capacidad de otorgar privilegios (usar con extrema precaución)
CREATE USER 'superadmin'@'localhost' IDENTIFIED BY 'SuperAdminPass!';
GRANT ALL PRIVILEGES ON *.* TO 'superadmin'@'localhost' WITH GRANT OPTION;

2. Seguridad de Red: Aislando su Base de Datos

Los controles a nivel de red son críticos para prevenir el acceso externo no autorizado a su servidor MySQL.

Configurar Cortafuegos

Permita conexiones al puerto predeterminado de MySQL (3306) solo desde direcciones IP o redes confiables. Bloquee todas las demás conexiones entrantes a este puerto.

Ejemplo (UFW en Linux):

sudo ufw enable
sudo ufw allow from 192.168.1.0/24 to any port 3306
sudo ufw deny 3306
sudo ufw status

Ejemplo (CentOS/RHEL con firewalld):

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --permanent --remove-port=3306/tcp --zone=public # Asegurar que no esté abierto globalmente
sudo firewall-cmd --reload

Asegurar Conexiones con SSL/TLS

Cifre todo el tráfico entre los clientes y el servidor MySQL usando SSL/TLS para prevenir la escucha y los ataques de intermediario (MitM). Esto es especialmente crucial para conexiones a través de redes no confiables.

Para habilitar SSL/TLS, normalmente necesita generar certificados y claves SSL, luego configurar su my.cnf:

# my.cnf
[mysqld]
ssl_ca=/etc/mysql/certs/ca.pem
ssl_cert=/etc/mysql/certs/server-cert.pem
ssl_key=/etc/mysql/certs/server-key.pem

Los clientes deben configurarse para conectarse usando SSL/TLS, a menudo con REQUIRE SSL en la declaración GRANT del usuario:

CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'SSLUserPass!';
GRANT SELECT ON `your_database`.* TO 'ssl_user'@'%' REQUIRE SSL;

Vincular a Direcciones IP Específicas

Por defecto, MySQL puede escuchar en todas las interfaces de red disponibles (0.0.0.0). Restríngalo para que escuche solo en las interfaces que necesitan aceptar conexiones (ej., localhost para aplicaciones locales, o una IP de red privada para conexiones internas).

# my.cnf
[mysqld]
bind-address = 127.0.0.1  # Solo para conexiones locales
# O
bind-address = 192.168.1.10  # Para una IP interna específica

Consejo: Si su aplicación y el servidor MySQL están en la misma máquina, bind-address = 127.0.0.1 (localhost) es la opción más segura, ya que evita completamente cualquier conexión externa.

3. Refuerzo del Archivo de Configuración (my.cnf / my.ini)

El archivo de configuración de MySQL (my.cnf en Linux, my.ini en Windows) ofrece numerosos parámetros para mejorar la seguridad.

Deshabilitar Funcionalidades No Utilizadas

Minimice la superficie de ataque deshabilitando funcionalidades no requeridas para su implementación.

  • local_infile = 0: Deshabilita LOAD DATA LOCAL INFILE, que de otro modo puede leer archivos del host cliente cuando tanto el cliente como el servidor lo permiten.
    [mysqld]
    local_infile = 0
    
  • skip-networking: Si su base de datos solo es accesada por aplicaciones en el mismo servidor, deshabilite la red por completo. Esto obliga a todas las conexiones a usar el socket Unix o tuberías con nombre.
    [mysqld]
    skip-networking
    
  • symbolic-links = 0: Previene el uso de enlaces simbólicos para tablespaces de bases de datos, que pueden ser explotados para acceder a archivos fuera del directorio de datos de MySQL.
    [mysqld]
    symbolic-links = 0
    
  • secure_file_priv: Restringe el directorio utilizado por operaciones de importación y exportación de archivos como LOAD DATA INFILE y SELECT ... INTO OUTFILE.
    [mysqld]
    secure_file_priv = /var/lib/mysql-files
    

Establezca secure_file_priv a un directorio dedicado propiedad de la cuenta de servicio de MySQL. No lo apunte a /tmp, un directorio de carga de aplicaciones, o una ruta a la que usuarios no confiables puedan escribir.

Evitar Secretos en Texto Plano en Archivos de Opciones

Los archivos de opciones del cliente pueden exponer accidentalmente contraseñas de bases de datos a cualquiera que pueda leerlos. Si debe almacenar credenciales para automatización, restrinja los permisos del archivo y use una cuenta dedicada de bajo privilegio.

chmod 600 /home/backup/.my.cnf
chown backup:backup /home/backup/.my.cnf

Para administración interactiva, prefiera solicitar la contraseña:

mysql -u admin -p

4. Parchear y Verificar el Servidor

La configuración de seguridad no salvará un servidor sin parches. Mantenga MySQL, las bibliotecas cliente y el sistema operativo actualizados a través de su proceso normal de paquetes o actualizaciones del proveedor.

Después de cambiar my.cnf, valide y reinicie durante una ventana de mantenimiento:

mysqld --validate-config
sudo systemctl restart mysql
sudo systemctl status mysql

Los nombres de paquetes y servicios varían según la distribución. Algunos sistemas usan mysqld en lugar de mysql.

5. Monitorear el Acceso y Revisar Privilegios

El refuerzo no termina después de la primera pasada. Revise cuentas y concesiones regularmente, especialmente después de cambios en aplicaciones o rotación de personal.

SELECT user, host, account_locked FROM mysql.user ORDER BY user, host;
SHOW GRANTS FOR 'my_app_user'@'localhost';

Vigile las cuentas que usan hosts %, privilegios amplios *.*, FILE, SUPER, SYSTEM_USER, o WITH GRANT OPTION. Esos privilegios pueden ser válidos para un pequeño número de cuentas administrativas, pero nunca deberían aparecer en usuarios de aplicaciones rutinarias.

Conclusión

Refuerce MySQL en capas. Comience con usuarios dedicados de mínimo privilegio, restrinja desde dónde pueden conectarse, cifre el tráfico cuando cruce una red, deshabilite funcionalidades riesgosas que no use, y mantenga el servidor parcheado. Luego programe revisiones de privilegios para que el acceso antiguo no se convierta silenciosamente en su próximo incidente.