Esta sección describe algunos temas generales de seguridad que hay que tener en cuenta, y qué se puede hacer para aumentar la seguridad de la instalación MySQL contra ataques o errores de uso. Para encontrar información específica sobre el sistema de control de accesos que MySQL utiliza para crear cuentas de usuarios y comprobar el acceso a las bases de datos, consulte Sección 5.6, “El sistema de privilegios de acceso de MySQL”.
Cualquiera que utilice MySQL en un ordenador conectado a Internet debería leer esta sección para evitar los errores de seguridad más comunes.
Al tratar el tema de la seguridad, hacemos hincapié en la necesidad de proteger totalmente la máquina completa (no únicamente el servidor MySQL) contra todos los tipos de ataques posibles; intercepción pasiva de paquetes, alteración, reproducción de comandos (playback), y denegación de servicio. Aquí no tratamos todos los aspectos de disponibilidad y tolerancia a fallos.
Para todas las conexiones, consultas, y otras operaciones que los usuarios pueden intentar realizar, MySQL utiliza seguridad basada en Listas de Control de Acceso (ACLs). También hay algún soporte para conexiones cifradas mediante SSL entre clientes y servidores MySQL. Muchos de los conceptos que aquí se exponen no son específicos de MySQL; las mismas ideas generales se pueden aplicar a cualquier aplicación.
Al ejecutar MySQL, siga siempre que sea posible estas recomendaciones:
-
¡No de nunca a nadie (excepto a la cuenta
root
de MySQL acceso a la tablauser
en la base de datosmysql
! Esto es crítico. La clave cifrada es la verdadera clave en MySQL. Cualquiera que sepa cual es la clave que hay en la tablauser
y tenga acceso a la máquina host de la cuenta registrada puede acceder fácilmente como ese usuario. -
Estudie el sistema de privilegios de acceso de MySQL. Las sentencias
GRANT
yREVOKE
se utilizan para controlar el acceso a MySQL. No otorgue más privilegios de los necesarios. Nunca otorgue privilegios a un mismo usuario sin tener en cuenta el equipo desde el que se conecta.Lista de comprobaciones:
-
Pruebe el comando
mysql -u root
. Si es capaz de conectar al servidor sin la necesidad de introducir una clave, tiene problemas. ¡Cualquiera puede conectar a su servidor MySQL como el usuarioroot
de MySQL con privilegios totales! Revise las instrucciones de instalación de MySQL, prestando atención en concreto a la información sobre establecer una clave para el usuarioroot
. Consulte Sección 2.9.3, “Hacer seguras las cuentas iniciales de MySQL”. -
Utilice la sentencia
SHOW GRANTS
y compruebe quién tiene acceso a qué. Después utilice la sentenciaREVOKE
para denegar los privilegios que no son necesarios.
-
-
No almacene ninguna clave sin cifrar en su base de datos. Si alguien tuviera acceso a su ordenador, el intruso podría obtener la lista completa de claves y utilizarlas. En vez de eso, utilice
MD5()
,SHA1()
, o cualquier otra función de hashing de un sentido. -
No elija claves que puedan aparecer en un diccionario. Existen programas especiales para romperlas. Incluso claves como ``xperro98'' son muy malas. Es mucho mejor ``oweei98'', que contiene la misma palabra ``perro'' pero escrita desplazándose una tecla a la izquierda en un teclado QWERTY convencional. Otro método es usar ``Mtupc'', que ha sido tomada de las primeras letras de cada palabra de la frase ``María tuvo un pequeño corderito.'' Así es fácil de recordar y escribir, pero difícil de adivinar para cualquiera que no la conozca.
-
Invierta en un firewall. Le protegerá de al menos el 50% de todos los tipos de vulnerabilidades de cualquier software. Ponga MySQL tras el firewall o en una zona desmilitarizada (DMZ).
Lista de comprobaciones:
-
Intente escanear sus puertos desde Internet utilizando una herramienta como
nmap
. MySQL utiliza el puerto 3306 por defecto. Este puerto no debería ser accesible desde lugares no confiables. Otra manera simple de probar si el puerte MySQL está abierto o no es intentar el siguiente comando desde alguna máquina remota, dondeserver_host
es la máquina en la que su servidor MySQL se está ejecutando:shell> telnet server_host 3306
Si consigue conectar y algunos carácteres extraños, el puerto está abierto, y debería cerrarlo en su firewall o router, a menos que tenga una buena razón para mantenerlo abierto. Si el comando
telnet
no consigue conectar o la conexión es rechazada, entonces el puerto se encuentra bloqueado, que es como queremos que esté.
-
-
No confíe en ningún dato enviado por los usuarios de sus aplicaciones. Pueden intentar engañar a su código introduciendo secuencias de carácteres especiales en formularios webs, URLs, o cualquier aplicación que haya desarrollado. Asegúrese de que su aplicación permance segura si un usuario introduce algo como ``
; DROP DATABASE mysql;
''. Este es un ejemplo algo extremo, pero los mayores agujeros de seguridad y pérdidas de datos pueden ocurrir como resultado de hackers utilizando técnicas similares, si no se está preparado para ellas.Un error común es proteger únicamente valores de tipo cadena de carácteres. Recuerde comprobar los datos numéricos también. Si una aplicación genera una consulta como
SELECT * FROM table WHERE ID=234
cuando un usuario introduce el valor234
, el usuario podría introducir el valor234 OR 1=1
para provocar que la aplicación genere la consultaSELECT * FROM table WHERE ID=234 OR 1=1
. Como resultado, el servidor extraerá todos los registros en la tabla. Esto, además de exponer cada registro, causa una carga excesiva en el servidor. La manera más simple de protegerse frente a este tipo de ataque es utilizar comillas simples alrededor de las constantes numéricas:SELECT * FROM table WHERE ID='234'
. Si el usuario entrase información extra, todo sería parte de la cadena de carácteres. En un contexto numérico, MySQL automáticamente convierte esta cadena en un número, y elimina cualquier carácter no númerico del final que la cadena pueda contener.A veces la gente piensa que si una base de datos contiene sólo datos de dominio público, no tiene por qué ser protegida. Esto es incorrecto. Aunque sea admitible mostrar cualquier registro de la base de datos, siempre se debería proteger contra ataques de tipo denegación de servicio (por ejemplo, aquellos que se basan en la técnica del párrafo precedente, que causan que el servidor malgaste recursos). Si no, el servidor podría quedar inservible para sus usuarios legítimos.
Lista de comprobaciones:
-
Intente introducir comillas simples y dobles ('
'
' y '"
') en todos sus formularios web. Si obtiene cualquier clase de error MySQL, investigue el problema sin demora. -
Intente modificar las URLs dinámicas añadiendo las cadenas
%22
('"
'),%23
('#
'), y%27
(''
'). -
Intente modificar los tipos de datos en las URLs dinámicas de tipos numéricos a alfanuméricos, usando los caracteres mostrados en los ejemplos previos. Su aplicaicón debería ser segura contra estos y otros ataques similares.
-
Intente introducir letras, espacios, y símbolos especiales en vez de números en los campos numeicos. Su aplicación debería eliminarlos antes de pasarlos a MySQL, o en todo caso generar un error. ¡Pasar valores sin comprobar a MySQL es muy peligroso!
-
Compruebe el tamaño de los datos antes de pasárselos a MySQL.
-
Haga que su aplicación se conecte a la base de datos utilizando un nombre de usuario diferente del que utiliza para tareas administrativas. No dé a sus aplicaciones ningún acceso que no necesiten.
-
-
Muchas interficies de programación de aplicaciones proveen alguna manera de preceder con carácteres de escape los caracteres especiales en sus datos. Usados adecuadamente, esto previene que los usuarios de las aplicaciones introduzcan valores que provoquen que la aplicación genere sentencias con efectos diferentes a los que usted pretendía:
-
API MySQL de C: Utilice la función
mysql_real_escape_string()
. -
MySQL++: Utilice los modificadores
escape
yquote
para streams -
PHP: Utilice la función
mysql_escape_string()
, que está basada en la función del mismo nombre de la API MySQL de C. (Con versiones anteriores a PHP 4.0.3, utiliceaddslashes()
en cambio.) En PHP 5, puede utilizar la extensiónmysqli
, que soporta los protocolo de autentificación y clave de acceso mejorados de MySQL, así como las sentencias preparadas con placeholders. -
DBI de Perl: Utilice el método
quote()
o utilice placeholders. -
JDBC de Java: Utilice un objeto
PreparedStatement
y placeholders.
Otras interficies de programación deberían tener capacidades similares.
-
-
No transmita datos sin cifrar por Internet. Esta información es accesible para cualquiera que tenga el tiempo y la habilidad para interceptarla y utilizarla para sus propios propósitos. En vez de eso, utilice un protocolo de cifrado como SSL o SSH. MySQL soporta conexiones SSL internas desde la versión 4.0.0. El redireccionamiento de puertos de SSH se puede utilizar para crear un tunel cifrado (y comprimido) para la comunicación.
-
Aprenda a utilizar las herramientas
tcpdump
ystrings
. En la mayoría de los casos, usted puede comprobar si los flujos de datos de MySQL están cifrados ejecutando un comando como el siguiente:shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
(Esto funciona en Linux, y debería funcionar, con pequeñas modificaciones en otros sistemas.) Atención: Si no ve los datos en formato de texto, esto no siempre quiere decir que la información esté realmente cifrada. Si necesita un alto nivel de seguridad, debería consultar a un experto en la materia.
Cuando se conecta a un servidor MySQL, debería utilizar una clave. La clave no se transmite en texto llano a través de la conexión. El tratamiento de las claves durante la conexión de un cliente ha sido mejorado en MySQL 4.1.1 para ser muy seguro. Si todavía está utilizando claves del tipo anterior a 4.1.1, el algoritmo de cifrado no es tan potente como el nuevo algoritmo; con un poco de esfuerzo un atacante inteligente que pueda interceptar el tráfico entre el cliente y el servidor podría romper la clave. (Consulte Sección 5.6.9, “Hashing de contraseñas en MySQL 4.1” para una explicación sobre los diferentes métodos de tratamiento de claves.) Si la conexión entre el cliente y el servidor pasa a través de una red no segura, debería utilizar un tunel SSH para cifrar la comunicación.
Toda la demás información se transmite como texto, y puede ser leida por cualquiera que pueda observar la conexión. Si esto le preocupa, utilice el protocolo comprimido para hacer que el tráfico sea mucho más difícil de descifrar. Para hacer la conexión aún más segura, debería utilizar SSH para conseguir una conexión TCP/IP cifrada entre el servidor MySQL y el cliente MySQL. Puede encontrar un cliente SSH Open Source en http://www.openssh.org/, y un cliente comercial en http://www.ssh.com/.
En MySQL 5.0, puede utilizar también el soporte interno de OpenSSL. Consulte Sección 5.7.7, “Usar conexiones seguras”.
Para convertir un sistema MySQL en seguro, debería considerar seriamente las siguientes sugerencias:
-
Utilice claves para todos los usuarios MySQL. Un programa cliente no conoce necesariamente la identidad de la persona utilizándolo. Es común en las aplicaciones cliente/servidor que el usuario pueda especificar cualquier nombre de usuario al programa cliente. Por ejemplo, cualquiera puede utilizar el programa mysql para conectarse como cualquier otra persona, simplemente invocándolo de la siguiente manera:
mysql -u
otro_usuario
nombre_bd
cuandootro_usuario
no tiene clave. Si todos los usuarios tienen una clave, conectarse utilizando la cuenta de otro usuario se vuelve mucho más difícil.Para cambiar la clave de un usuario, utilice la sentencia
SET PASSWORD
. También es posible alterar la tablauser
en la base de datosmysql
directamente. Por ejemplo, para cambiar la clave de todas las cuentas MySQL que tienen por nombre de usuarioroot
, haga lo siguiente:shell> mysql -u root mysql> UPDATE mysql.user SET Password=PASSWORD('
newpwd
') -> WHERE User='root'; mysql> FLUSH PRIVILEGES; -
Nunca ejecute el servidor MySQL con el usuario
root
de Unix. Esto es extremadamente peligroso porque cualquier usuario con el privilegioFILE
es capaz de crar ficheros comoroot
(por ejemplo,~root/.bashrc
). Para prevenir esto, mysqld rechaza ejecutarse comoroot
a menos que se utilice explícitamente la opción--user=root
.En vez de eso, mysqld puede (y debe) ser ejecutado mediante un usuario normal sin privilegios. Puede crear una cuenta de Unix específica llamada
mysql
para hacelo todo aún más seguro. Utilice esta cuenta tan solo para administrar MySQL. Para ejecutar mysqld mediante un usuario de Unix diferente, añada la opciónuser
que especifica el nombre de usuario al grupo[mysqld]
del fichero de opciones/etc/my.cnf
o al fichero de opcionesmy.cnf
en el directorio de datos del servidor. Por ejemplo:[mysqld] user=mysql
Esto provoca que el servidor se inicie mediante el usuario designado, lo ejecute usted manualmente o mediante mysqld_safe o mysql.server. Para más detalles, consulte Sección A.3.2, “Cómo correr MySQL como usuario normal”.
Ejecutar mysqld como un usuario Unix diferente de
root
no significa que necesite cambiar el usuarioroot
de la tablauser
. Los usuarios de las cuentas MySQL no tienen nada que ver con los usuarios de las cuentas Unix. -
No permita el uso de enlaces simbólicos a tablas. (Esto puede desactivarse con la opción
--skip-symbolic-links
.) Esto es especialmente importante si ejecuta mysqld comoroot
, porque cualquiera que tenga acceso de escritura al directorio de datos del servidor ¡podría entonces borrar cualquier fichero en el sistema!. Consulte Sección 7.6.1.2, “Utilización de enlaces simbólicos para tablas en Unix”. -
Asegúrese de que el único usuario Unix con permisos de lectura o escritura en los directorios de la base de datos es el usuario que ejecuta mysqld.
-
No otorgue los privilegios
PROCESS
oSUPER
a usuarios no-administrativos. La salida del de mysqladmin processlist muestra el texto de cualquier sentencia que se esté ejecutando, así que cualquier usuario al que se permita ejecutar ese comando puede ser capaz de ver si otro usuario ejecuta una sentenciaUPDATE user SET password=PASSWORD('not_secure')
.mysqld reserva una conexión extra para usuarios que tengan el privlegio
SUPER
, así que un usuarioroot
puede conectarse y comprobar la actividad del servidor aún cuando todas las conexiones normales estén en uso.El privilegio
SUPER
puede utilizarse para cerrar conexiones de cliente, cambiar el funcionamiento del servidor modificando el valor de variables del sistema, y controlar servidores de replicación. -
No otorgue el privilegio
FILE
a usuarios no-administrativos. Cualquier usuario que posea este privilegio puede escribir un archivo en cualquier de lugar del sistema de ficheros con los privilegios del demonio mysqld. Para hacer esto un poco más seguro, los archivos generados conSELECT ... INTO OUTFILE
no sobreescriben archivos existentes, y pueden ser escritos por cualquiera.El privilegio
FILE
puede también ser utilizado para leer cualquier archivos que sea legible por cualquiera o accesible para el usuario Unix que ejecuta el servidor. Con este privilegio, podría por ejemplo leer cualquier fichero e insertarlo en una tabla de la base de datos. Esto podría utilizarse, por ejemplo, utilizandoLOAD DATA
para cargar/etc/passwd
en una tabla, que podría ser mostrada después con unSELECT
. -
Si no confía en sus DNS, podría utilizar números IP en vez de nombres en las tablas de permisos (tablas grant). En cualquier caso, debería ser muy cuidadoso en crear registros en las tablas de permiso utilizando nombres que contengan carácteres comodín.
-
Si quiere restringir el número de conexiones permitidas para una misma cuenta, puede hacerlo estableciando la variable
max_user_connections
de mysqld. La sentenciaGRANT
también soporta opciones de control de recursos para limitar la extensión de uso de servidor permitido a una cuenta. Consulte Sección 13.5.1.3, “Sintaxis deGRANT
yREVOKE
”.
Las siguientes opciones de mysqld afectan a la seguridad:
-
--allow-suspicious-udfs
Esta opción cotrola si las funciones definidas por el usuario que sólo tienen un símbolo
xxx
para la función principal se pueden cargar. Por defecto, la opción está desactivada y sólo UDFs que tengan al menos un símbolo auxiliar pueden cargarse. Esto previene intentos de cargar funciones desde ficheros objeto compartidos que no contegan UDFs legítimos. Para MySQL 5.0, esta opción se añadió en MySQL 5.0.3. Consulte Sección 27.2.3.6, “Precauciones de seguridad en funciones definidas por usuarios”. -
--local-infile[={0|1}]
Si arranca el servidor con
--local-infile=0
, los clientes no pueden usarLOCAL
en comandosLOAD DATA
. Consulte Sección 5.5.4, “Cuestiones relacionadas con la seguridad yLOAD DATA LOCAL
”. -
--old-passwords
Fuerza al servidor a generar hashes de contraseñas cortos (pre-4.1) para las nuevas contraseñas. Esto es útil para compatibilidad cuando el servidor debe soportar antiguos programas cliente. Consulte Sección 5.6.9, “Hashing de contraseñas en MySQL 4.1”.
-
(OBSOLETO)
--safe-show-database
En versiones previas de MySQL, esta opción provoca que el comando
SHOW DATABASES
muestre los nombers de sólo aquellas bases de datos para las que el usuario tiene algún tipo de privilegio. En MySQL 5.0, esta opción no está disponible ya que es el comportamiento por defecto, y hay un privilegioSHOW DATABASES
que puede usarse para controlar el acceso a los nombres de las bases de datos para cada cuenta. Consulte Sección 13.5.1.3, “Sintaxis deGRANT
yREVOKE
”. -
--safe-user-create
Si está activada, un usuario no puede crear nuevos usuarios con el comando
GRANT
a no ser que el usuario tenga el privilegioINSERT
para la tablamysql.user
. Si desea que un usuario tenga la habilidad de crear nuevos usuarios con los privilegios que el usuario tiene derecho a otorgar, debe otorgar al usuario el siguiente privilegio:mysql> GRANT INSERT(user) ON mysql.user TO '
nombre_usuario
'@'nombre_host
';Esto asegura que el usuario no pueda cambiar ninguna columna de privilegios directamente, pero debe usar el comando
GRANT
para dar privilegios a otros usuarios. -
--secure-auth
Desactiva autenticación para cuentas que usen antiguas contraseñas (pre-4.1)
-
--skip-grant-tables
Esta opción hace que el servidor no use el sistema de privilegios en absoluto. Esto da a todo el mundo acceso total a todas las bases de datos! (Puede decirle a un servidor en ejecución que arranque usando las tablas de permisos de nuevo usando mysqladmin flush-privileges o el comando mysqladmin reload, o mediante el comando
FLUSH PRIVILEGES
.) -
--skip-name-resolve
Los nombres de equipo no se resuelven. Todo valor en la columna
Host
en la tabla de permisos deben ser números IP olocalhost
. -
--skip-networking
No permite conexiones TCP/IP a través de la red. Todas las conexiones a mysqld se realizan mediante ficheros socket de Unix.
-
--skip-show-database
Con esta opción, el comando
SHOW DATABASES
se permite sólo a usuarios que tengan el privilegioSHOW DATABASES
, y el comando muestra todos los nombres de bases de datos. Sin esta opción ,SHOW DATABASES
está permitido a todos los usuarios, pero muestra cada nombre de base de datos sólo si el usuario tiene el privilegioSHOW DATABASES
o algún privilegio para la base de datos.
El comando LOAD DATA
puede cargar un fichero
que esté localizado en el equipo servidor, o puede cargar un
fichero localizado en el equipo cliente cuando se especifica la
palabra clave LOCAL
.
Hay dos aspectos de seguridad potenciales al soportar la
versión LOCAL
de los comandos LOAD
DATA
:
-
La transferencia del fichero desde el equipo cliente al equipo servidor se inicia mediante el servidor MySQL. En teoría, puede construirse un servidor modificado de forma que le diga al programa cliente que transfiera un fichero elegido por el servidor en lugar de el fichero especificado por el cliente en el comando
LOAD DATA
. Tal servidor podría acceder a cualquier fichero en el equipo cliente al que el usuario cliente tuviese acceso de lectura. -
En un entorno Web en el que los clientes se conecten mediante un servidor Web, un usuario podría usar
LOAD DATA LOCAL
para leer cualquier fichero al que el servidor Web tuviese acceso de lectura (asumiendo que el usuario puediese ejecutar cualquier comando contra el servidor SQL). En este entorno, el cliente respecto al servidor MySQL es el servidor Web, no el programa ejectuado por el usuario para conectar al servidor Web.
Para tratar estos problemas, hemos cambiado el funcionamiento de
LOAD DATA LOCAL
en MySQL 3.23.49 y MySQL
4.0.2 (4.0.13 en Windows):
-
Por defecto, todos los clientes MySQL y bibliotecas en distribuciones binarias se compilan con la opción
--enable-local-infile
para ser compatible con la versión MySQL 3.23.48 y anteriores. -
Si compila MySQL de los ficheros fuentes pero no usa la opción
--enable-local-infile
para configure,LOAD DATA LOCAL
no puede usarse por ningún cliente a no ser que se escriba explícitamente para invocarmysql_options(... MYSQL_OPT_LOCAL_INFILE, 0)
. Consulte Sección 24.3.3.44, “mysql_options()
”. -
Puede desactivar todos los comandos
LOAD DATA LOCAL
desde el lado del servidor arrancando mysqld con la opción--local-infile=0
. -
Para el cliente de línea de comando mysql,
LOAD DATA LOCAL
puede activarse especificando la opción--local-infile[=1]
, o deshabilitarse con la opción--local-infile=0
. De forma similar, para mysqlimport, las opciones--local
o-L
permite la carga de datos locales. En cualquier caso, el uso exitoso de una operación de carga local requiere que el servidor lo permita. -
Si usa
LOAD DATA LOCAL
en scripts de Perl scripts u otros programsa que lean del grupo[client]
en los ficheros de opciones, puede añadir la opciónlocal-infile=1
a ese grupo. De todos modos, para evitar que esto cause problemas en programas que no entiendanlocal-infile
, especifíquelo usando el prefijoloose-
:[client] loose-local-infile=1
-
Si
LOAD DATA LOCAL INFILE
está desactivado, tanto en el servidor o el cliente, un cliente que trate de ejecutar dicho comando recibe el siguiente mensaje de error:ERROR 1148: The used command is not allowed with this MySQL version