5.5. Cuestiones de seguridad general

MySQL 5.0

5.5. Cuestiones de seguridad general

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”.

5.5.1. Guía de seguridad general

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 de MySQL acceso a la tabla en la base de datos ! Esto es crítico. La clave cifrada es la verdadera clave en MySQL. Cualquiera que sepa cual es la clave que hay en la tabla 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 y 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 . 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 usuario 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 usuario . Consulte Sección 2.9.3, “Hacer seguras las cuentas iniciales de MySQL”.

    • Utilice la sentencia y compruebe quién tiene acceso a qué. Después utilice la sentencia 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 , , 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 . 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, donde 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 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 ``''. 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 cuando un usuario introduce el valor , el usuario podría introducir el valor para provocar que la aplicación genere la consulta . 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: . 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 (''), (''), y ('').

    • 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++: Utilice los modificadores y para streams

    • PHP: Utilice la función , que está basada en la función del mismo nombre de la API MySQL de C. (Con versiones anteriores a PHP 4.0.3, utilice en cambio.) En PHP 5, puede utilizar la extensión , 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 o utilice placeholders.

    • JDBC de Java: Utilice un objeto 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 y . 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.

5.5.2. Hacer que MySQL sea seguro contra ataques

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: cuando 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 . También es posible alterar la tabla en la base de datos directamente. Por ejemplo, para cambiar la clave de todas las cuentas MySQL que tienen por nombre de usuario , haga lo siguiente:

    shell> mysql -u root
    mysql> UPDATE mysql.user SET
    Password=PASSWORD('')
        -> WHERE User='root';
    mysql> FLUSH PRIVILEGES;
    
  • Nunca ejecute el servidor MySQL con el usuario de Unix. Esto es extremadamente peligroso porque cualquier usuario con el privilegio es capaz de crar ficheros como (por ejemplo, ). Para prevenir esto, mysqld rechaza ejecutarse como a menos que se utilice explícitamente la opción .

    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 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ón que especifica el nombre de usuario al grupo del fichero de opciones o al fichero de opciones 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 no significa que necesite cambiar el usuario de la tabla . 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 .) Esto es especialmente importante si ejecuta mysqld como , 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 o 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 sentencia .

    mysqld reserva una conexión extra para usuarios que tengan el privlegio , así que un usuario puede conectarse y comprobar la actividad del servidor aún cuando todas las conexiones normales estén en uso.

    El privilegio 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 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 con no sobreescriben archivos existentes, y pueden ser escritos por cualquiera.

    El privilegio 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, utilizando para cargar en una tabla, que podría ser mostrada después con un .

  • 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 de mysqld. La sentencia 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 de y .

5.5.3. Opciones de arranque para mysqld relacionadas con la seguridad

Las siguientes opciones de mysqld afectan a la seguridad:

  • Esta opción cotrola si las funciones definidas por el usuario que sólo tienen un símbolo 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”.

  • Si arranca el servidor con , los clientes no pueden usar en comandos . Consulte Sección 5.5.4, “Cuestiones relacionadas con la seguridad y .

  • 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)

    En versiones previas de MySQL, esta opción provoca que el comando 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 privilegio 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 de y .

  • Si está activada, un usuario no puede crear nuevos usuarios con el comando a no ser que el usuario tenga el privilegio para la tabla . 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 ''@'';
    

    Esto asegura que el usuario no pueda cambiar ninguna columna de privilegios directamente, pero debe usar el comando para dar privilegios a otros usuarios.

  • Desactiva autenticación para cuentas que usen antiguas contraseñas (pre-4.1)

  • 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 .)

  • Los nombres de equipo no se resuelven. Todo valor en la columna en la tabla de permisos deben ser números IP o .

  • No permite conexiones TCP/IP a través de la red. Todas las conexiones a mysqld se realizan mediante ficheros socket de Unix.

  • Con esta opción, el comando se permite sólo a usuarios que tengan el privilegio , y el comando muestra todos los nombres de bases de datos. Sin esta opción , está permitido a todos los usuarios, pero muestra cada nombre de base de datos sólo si el usuario tiene el privilegio o algún privilegio para la base de datos.

5.5.4. Cuestiones relacionadas con la seguridad y LOAD DATA LOCAL

El comando 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 .

Hay dos aspectos de seguridad potenciales al soportar la versión de los comandos :

  • 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 . 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 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 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 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 para configure, no puede usarse por ningún cliente a no ser que se escriba explícitamente para invocar . Consulte Sección 24.3.3.44, “.

  • Puede desactivar todos los comandos desde el lado del servidor arrancando mysqld con la opción .

  • Para el cliente de línea de comando mysql, puede activarse especificando la opción , o deshabilitarse con la opción . De forma similar, para mysqlimport, las opciones o 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 en scripts de Perl scripts u otros programsa que lean del grupo en los ficheros de opciones, puede añadir la opción a ese grupo. De todos modos, para evitar que esto cause problemas en programas que no entiendan , especifíquelo usando el prefijo :

    [client]
    loose-local-infile=1
    
  • Si 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