Suprime mensajes de advertencia usando mysql desde Terminal, pero la contraseña está escrita en script bash

273

Cuando intenté ejecutar el siguiente comando en MySQL desde Terminal:

mysql -u $user -p$password -e "statement"

La ejecución funciona como se esperaba, pero siempre emite una advertencia:

Advertencia: el uso de una contraseña en la interfaz de línea de comandos puede ser inseguro.

Sin embargo, tengo que llevar a cabo la declaración anterior usando una variable de entorno ( $password) que almacena mi contraseña, porque quiero ejecutar el comando iterativamente en el script bash desde Terminal, y definitivamente no me gusta la idea de esperar que aparezca un mensaje. y obligándome a ingresar mi contraseña 50 o 100 veces en un solo script. Así que aquí está mi pregunta:

  • ¿Es factible suprimir la advertencia? El comando funciona correctamente como dije, pero la ventana se vuelve bastante desordenada cuando paso y ejecuto el comando 50 o 100 veces.

  • ¿Debo obedecer el mensaje de advertencia y NO escribir mi contraseña en mi script? Si ese es el caso, ¿tengo que escribir mi contraseña cada vez que el mensaje me obliga a hacerlo?

Correr man mysqlno ayuda, solo decir

--show-warnings
Causar que se muestren advertencias después de cada declaración si hay alguna. Esta opción se aplica al modo interactivo y por lotes.

y no menciona nada acerca de cómo desactivar la funcionalidad, si no me falta algo.

Estoy en OS X 10.9.1 Mavericks y uso MySQL 5.6 de homebrew.

Blaszard
fuente
14
La forma recomendada es almacenar su contraseña en un archivo de opciones (algo así como [client] password=my_passworden ~/.my.cnf). Seguramente también tiene algunas implicaciones de seguridad, pero al menos no es accesible para cualquiera que pueda ejecutar ps, y usted tiene control sobre esto con permisos de archivo.
Anton Kovalenko
44
mysql -u root password root -e "statement" > /dev/null?
Ah, por cierto, también puedes usar algo como Python pexcept. Puede hacer inserciones de terminal y también manejar los comentarios que da el comando. De esta forma, puede omitir esa salida detallada y la tira de la salida real que desea :)
66
La forma recomendada por la OMI penaliza a los que hacen lo correcto para proteger a los que hacen lo incorrecto. Si la contraseña se almacena dentro de un archivo de script, no aparecerá con ps ni en ningún registro. Esa es la forma correcta de hacer esto. Poner el archivo en un archivo externo ayuda a aquellos que sincronizarían la contraseña, pero eso es malo para empezar. Mientras tanto, los scripts que se han estado ejecutando durante años ahora fallan y tenemos que modificarlos solo porque esta advertencia aparece en el stderr.
Nestor Urquiza
2
Para el método recomendado que no almacena la contraseña en claro, se detalla en dev.mysql.com/doc/refman/5.6/en/mysql-config-editor.html
anthony

Respuestas:

250

Si su versión de cliente / servidor MySQL es una forma 5.6.xa de evitar que el mensaje de ADVERTENCIA esté utilizando las herramientas mysql_config_editor :

mysql_config_editor set --login-path=local --host=localhost --user=username --password

Luego puede usar en su script de shell:

mysql --login-path=local  -e "statement"

En vez de:

mysql -u username -p pass -e "statement"
Cristian Porta
fuente
28
Recuerde que --login-pathtiene que venir antes que todos los demás argumentos. Estaba intentando mysqldump --tables --login-path=localy obteniendo el error unknown variable 'login-path=local'.
Tulio
El cliente de línea de comando mysql buscará debajo de la ruta de acceso de 'cliente' por defecto. Puede simplificar las instrucciones para "mysql -e 'instrucción'" haciendo un pequeño cambio.
Morgan Tocker
2
Esto funciona bien si ejecutamos directamente el archivo shell pero no funciona si se llama desde crontab
Nabeel Arshad
1
@NabeelArshad Creo que esto se debe a que en su crontab el "hogar" para el usuario no está configurado (ENV vars en general) por lo que en el crontab el cliente no puede encontrar el correcto ~ / .mylogin.cnf
Cristian Porta
1
@NamGVU, no estoy seguro, sin embargo, creo que esta solución almacena contraseñas cifradas.
zhekaus
209

Yo uso algo como:

mysql --defaults-extra-file=/path/to/config.cnf

o

mysqldump --defaults-extra-file=/path/to/config.cnf 

Donde config.cnf contiene:

[client]
user = whatever
password = whatever
host = whatever

Esto le permite tener múltiples archivos de configuración, para diferentes servidores / roles / bases de datos. El uso de ~ / .my.cnf solo le permitirá tener un conjunto de configuraciones (aunque puede ser un conjunto útil de valores predeterminados).

Si está en una distribución basada en Debian y se ejecuta como root, puede omitir lo anterior y simplemente usar /etc/mysql/debian.cnf para entrar ...:

mysql --defaults-extra-file=/etc/mysql/debian.cnf

David Goodwin
fuente
12
Nota: --defaults-extra-filedebe ser la primera opción, de lo contrario mysql se queja mysqldump: unknown variable 'defaults-extra-file.
Pevik
44
Impresionante alternativa a la respuesta aceptada. Definitivamente no establezca la MYSQL_PWDvariable ...
DudeOnRock
1
Definitivamente una buena opción para versiones inferiores a 5.6. De lo contrario, iría con la respuesta aceptada.
dkniffin
21
Una alternativa a hacer un archivo temporal .cnf es hacer esto en Bash: mysql --defaults-extra-file=<(printf "[client]\nuser = %s\npassword = %s" "$user" "$pwd") -e "statement". Dado que printfBash lo ejecuta directamente, no aparece en ps.
Dave James Miller el
3
Necesitaba usar en --defaults-filelugar de --defaults-extra-file, porque este último daba preferencia a la configuración en ~ / .my.cnf.
Roger Dueck
186

Un método que es conveniente (pero igualmente inseguro) es usar:

MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"

Tenga en cuenta que los documentos oficiales recomiendan no hacerlo.
Consulte 6.1.2.1 Pautas para el usuario final para la seguridad de la contraseña (Manual Mysql para la versión 5.6) :

Almacenar su contraseña en la MYSQL_PWDvariable de entorno

Este método de especificar su contraseña de MySQL debe considerarse extremadamente inseguro y no debe usarse. Algunas versiones de ps incluyen una opción para mostrar el entorno de los procesos en ejecución. En algunos sistemas, si configura MYSQL_PWD, su contraseña está expuesta a cualquier otro usuario que ejecute ps . Incluso en sistemas sin tal versión de ps , no es prudente suponer que no hay otros métodos por los cuales los usuarios puedan examinar los entornos de proceso.

Ivan Dokov
fuente
66
Esto no funciona en mi script bash:Access denied for user 'root'@'localhost' (using password: NO)
rubo77
24
En un script, necesitas hacerlo export MYSQL_PWD=whatever.
Disturbios
2
Como mi consulta es muy rápida, opté por esta opción. Luego lo configuré en algo falso después de ejecutar la consulta.
TimH - Codidact
11
En un script que no necesita ejecutar export, simplemente colóquelo todo en una línea:MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"
JD
1
@JD: funciona para mí en Ubuntu 16.04 con MySQL 5.7.21.
mivk
70

Si desea utilizar una contraseña en la línea de comando, he descubierto que esto funciona para filtrar el mensaje de error específico:

mysqlcommand 2>&1 | grep -v "Warning: Using a password"

Básicamente es redirigir el error estándar a la salida estándar, y usar grep para eliminar todas las líneas que coinciden con "Advertencia: Usar una contraseña".

De esta manera, puede ver cualquier otra salida, incluidos los errores. Lo uso para varios scripts de shell, etc.

johnmontfx
fuente
Esta es una excelente solución para usar en tareas de una sola línea llamadas en otras tareas, como la creación de una tarea Rake para una implementación de Capistrano.
JakeGould
2
Excelente y simple para silenciar ese mensaje, no es necesario tocar nada en la configuración de MySQL.
ajaaskel
¿Cómo usaría esto con mysqldump donde ya tengo una redirección para el SQL?
MacroMan
1
Esta es una solución realmente mala en comparación con las otras aquí. Puede fallar con cualquier versión posterior de MySQL si el texto cambia, puede que tampoco funcione en otra configuración regional.
yktoo
42

Así es como obtuve mi script bash para que mis copias de seguridad diarias de la base de datos mysqldump funcionen de manera más segura. Esta es una expansión de la gran respuesta de Cristian Porta.

  1. Primero use mysql_config_editor (viene con mysql 5.6+) para configurar el archivo de contraseña cifrado. Supongamos que su nombre de usuario es "db_user". Ejecutando desde el indicador de comandos de la shell:

    mysql_config_editor set --login-path=local --host=localhost --user=db_user --password

    Solicita la contraseña. Una vez que lo ingrese, el usuario / pase se guardará cifrado en suhome/system_username/.mylogin.cnf

    Por supuesto, cambie "system_username" a su nombre de usuario en el servidor.

  2. Cambie su script bash de esto:

    mysqldump -u db_user -pInsecurePassword my_database | gzip > db_backup.tar.gz

    a esto:

    mysqldump --login-path=local my_database | gzip > db_backup.tar.gz

No más contraseñas expuestas.

Buttle Butkus
fuente
10

La forma más fácil es

mysql -u root -pMYPASSWORD -e "show databases" 2>/dev/null
JavaGuy
fuente
43
El problema es que esto también suprimirá errores legítimos en su script.
man910
44
También puede crear un archivo de registro 2> /var/log/myscript.log para registrar esos errores.
Skamasle
1
utilizar 2>/dev/null | grep -v "mysql: [Warning] Using a password on the command line interface can be insecure."para suprimir solo la advertencia en cuestión
Hafenkranich
10

También puede ejecutar mysql_config_editor en su script para pasar la contraseña al especificar la ruta de inicio de sesión

expect -c "
spawn mysql_config_editor set --login-path=$mySqlUser --host=localhost --user=$mySqlUser --password
expect -nocase \"Enter password:\" {send \"$mySqlPassword\r\"; interact}
"

Esto inicia una sesión de espera que se puede usar en scripts para interactuar con las indicaciones

Ver esta publicación

phylanx
fuente
¿Eso '>' realmente está destinado a estar allí?
David Goodwin
sí '>' está destinado a estar allí para que mysql_config_editor tome datos de stdout. Lo que se pasa de stdout a mysql_config_editor es la contraseña que desea que tenga este usuario Sin el '>', entonces lo que sucede es que el comando echo se analiza y todo lo que vería es todo después del comando echo
phylanx
Entonces, ¿quieres usar el operador de tubería "|", ¿verdad? Al menos, en * nix y DOS, ">" capturará el STDOUT y lo escribirá en un archivo llamado "mysql_config_editor" en el directorio de trabajo actual.
Jay Dansand
Sí, tienes razón, he editado mi respuesta original
phylanx
7

ok, solución sin archivos temporales ni nada:

mysql --defaults-extra-file=<(echo $'[client]\npassword='"$password") -u $user -e "statement"

es similar a lo que otros han mencionado, pero aquí no necesita un archivo real, esta parte del comando falsifica el archivo: <(echo ...) (observe que no hay espacio en el medio de<(

santiago arizti
fuente
esto no funciona si ya tiene un .my.cnfarchivo ~/.con una entrada de contraseña
santiago arizti
5
shell> mysql_config_editor set --login-path=local
     --host=localhost --user=localuser --password
Enter password: enter password "localpass" here
shell> mysql_config_editor set --login-path=remote
     --host=remote.example.com --user=remoteuser --password
Enter password: enter password "remotepass" here

Para ver lo que mysql_config_editor escribió en el archivo .mylogin.cnf, use el comando de impresión:

shell> mysql_config_editor print --all
[local]
user = localuser
password = *****
host = localhost
[remote]
user = remoteuser
password = *****
host = remote.example.com

El comando de impresión muestra cada ruta de inicio de sesión como un conjunto de líneas que comienzan con un encabezado de grupo que indica el nombre de la ruta de inicio de sesión entre corchetes, seguido de los valores de opción para la ruta de inicio de sesión. Los valores de las contraseñas están enmascarados y no aparecen como texto claro.

Como se muestra en los ejemplos anteriores, el archivo .mylogin.cnf puede contener múltiples rutas de inicio de sesión. De esta manera, mysql_config_editor facilita la configuración de múltiples "personalidades" para conectarse a diferentes servidores MySQL. Cualquiera de estos puede seleccionarse por nombre más tarde utilizando la opción --login-path cuando invocas un programa cliente. Por ejemplo, para conectarse al servidor local, use este comando:

shell> mysql --login-path=local

Para conectarse al servidor remoto, use este comando:

shell> mysql --login-path=remote
Beta
fuente
¿Qué sucede si quiero ejecutar un comando mysqldump como usuario de www-data? www-data no tiene directorio de inicio ... ¿cómo configuro mysql_config_editor para el usuario de www-data?
lewis4u
5

De https://gist.github.com/nestoru/4f684f206c399894952d

# Let us consider the following typical mysql backup script:
mysqldump --routines --no-data -h $mysqlHost -P $mysqlPort -u $mysqlUser -p$mysqlPassword $database

# It succeeds but stderr will get:
# Warning: Using a password on the command line interface can be insecure.
# You can fix this with the below hack:
credentialsFile=/mysql-credentials.cnf
echo "[client]" > $credentialsFile
echo "user=$mysqlUser" >> $credentialsFile
echo "password=$mysqlPassword" >> $credentialsFile
echo "host=$mysqlHost" >> $credentialsFile
mysqldump --defaults-extra-file=$credentialsFile --routines --no-data $database

# This should not be IMO an error. It is just a 'considered best practice'
# Read more from http://thinkinginsoftware.blogspot.com/2015/10/solution-for-mysql-warning-using.html
Néstor Urquiza
fuente
3

Otra alternativa es usar sshpass para invocar mysql, por ejemplo:

sshpass -p topsecret mysql -u root -p username -e 'statement'
lewiz
fuente
Parece funcionar, pero tienes que eliminar 'nombre de usuario' de la línea de comando, ¿no?
e2-e4
3

Un simple script de workaroud. Nombre este "mysql" y póngalo en su camino antes de "/ usr / bin". Variantes obvias para otros comandos, o si el texto de advertencia es diferente.

#!/bin/sh

(
(
(
(
(
    /usr/bin/mysql "$@"
) 1>&9 
) 2>&1
) | fgrep -v 'mysql: [Warning] Using a password on the command line interface can be insecure.'
) 1>&2 
) 9>&1
David G.
fuente
3
Si bien esta respuesta es un poco complicada, ¡acabo de votarla porque me molesta mucho ver respuestas que no son explícitamente incorrectas o son un poco poco convencionales conseguir votos negativos sin comentarios! ¡No es de extrañar que David no haya respondido ninguna otra pregunta! Saltó y trató de ayudar con una solución novedosa, ¡y ha sido golpeado sin explicación alguna por qué! ¡Votantes anónimos de FU que no dejan comentarios!
Jeremy Davis
3
+1 de acuerdo Jeremy Davis. Esto es complicado, pero cuando se deja sin otra opción, esto puede ser aceptable. ¡Definitivamente no está mal, a diferencia de desactivar las advertencias, que tiene que ser la idea más estúpida!
Ben McIntyre
1
@JeremyDavis Sí, esto fue complicado, principalmente porque quería mostrar el trabajo. Posiblemente podría hacerse sin paréntesis, pero podría haber sido menos claro. Esta fue también mi primera actividad no lectora en todo el intercambio de pila ... después de lo cual no lo toqué durante mucho tiempo. Su comentario fue definitivamente apreciado.
David G.
@DavidG. - Me alegra que mi comentario haya sido valioso para ti. También es bueno ver que has vuelto y que tu respuesta ahora está en territorio positivo. Personalmente, no creo que deba permitirse votar sin comentarios ... ¿Cómo se supone que alguien debe aprender cuando son criticados por intentarlo?
Jeremy Davis
Dicho esto, volviendo a mirar su respuesta, no estoy convencido de que una solución permanente (esencialmente envolviendo mysql) a un problema temporal (suprimiendo un mensaje de error para usar en un solo script) sea la mejor manera de hacerlo. IMO envolver mysql en una función dentro del script (usar su método aquí estaría bien) es un enfoque superior. My 2c ... :)
Jeremy Davis
3

Aquí hay una solución para Docker en un script / bin / sh:

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[cliente]"> /root/mysql-credentials.cnf'

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "user = root" >> /root/mysql-credentials.cnf'

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "contraseña = $ MYSQL_ROOT_PASSWORD" >> /root/mysql-credentials.cnf'

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec mysqldump --defaults-extra-file = / root / mysql-credentials.cnf --todas las bases de datos'

Reemplace [MYSQL_CONTAINER_NAME] y asegúrese de que la variable de entorno MYSQL_ROOT_PASSWORD esté configurada en su contenedor.

Espero que te ayude como me podría ayudar!

pcmanprogrammeur
fuente
No está mal. Acabo de usar una llamada con un retorno, por ejemplo, docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[client] [RETURN HERE] password=pa55" > /root/defaults'usar el --defaults-fileya recoge la raíz también.
Matthew Wilcoxson el
3

También puede simplemente redirigir la salida STDERR de error estándar a / dev / null

Entonces solo hazlo:

mysql -u $user -p$password -e "statement" 2> /dev/null

Joseph Shih
fuente
77
Evitaría
1

Personalmente, uso el contenedor de script para detectar ese error. Aquí está el ejemplo de código:

#!/bin/bash

#echo $@ | cat >> /home/mysqldump.log 2>/dev/null
ERR_FILE=/tmp/tmp_mdump.err

# Execute dumper
/usr/bin/mysqldump $@ 2>$ERR_FILE

# Determine error and remove tmp file
ERROR=`cat $ERR_FILE`
rm $ERR_FILE

# Handle an error
if [ "" != "$ERROR" ]; then

        # Error occured
        if [ "Warning: Using a password on the command line interface can be insecure." != "$ERROR" ]; then
                echo $ERROR >&2
                exit 1
        fi
fi
Y
fuente
1

Para PowerShell ( pwshno bash), esta fue una solución bastante rube-goldberg ... Mi primer intento fue ajustar las llamadas mysqlen una try/catchfunción, pero debido a un comportamiento extraño en el manejo de errores de PowerShell , esto no fue viable.

La solución fue reemplazar el $ErrorActionPreferencesuficiente sólo el tiempo para combinar y captura STDERRy STDOUTy análisis sintáctico de la palabra ERRORy re-tiro, según sea necesario. La razón por la que no pudimos detectar y liberar "^mysql.*Warning.*password"es porque PowerShell maneja y genera el error como una transmisión, por lo que debe capturarlo todo para filtrar y volver a lanzar. : /

Function CallMySQL() {
    # Cache the error action preference
    $_temp = $ErrorActionPreference
    $ErrorActionPreference = "Continue"

    # Capture all output from mysql
    $output = (&mysql --user=foo --password=bar 2>&1)

    # Restore the error action preference
    $ErrorActionPreference = $_temp

    if ($output -match "ERROR") {
        throw $output
    } elseif($output) {
        "   Swallowing $output"
    } else {
        "   No output"
    }
}

Nota: PowerShell está disponible para Unix, por lo que esta solución es multiplataforma. Se puede adaptar bashcon algunas modificaciones menores de sintaxis.

Advertencia: hay docenas de casos extremos en los que esto no funcionará, como mensajes de error en inglés o declaraciones que devuelven la palabra ERRORen cualquier parte de la salida, pero fue suficiente para tragar la advertencia para una llamada básica mysqlsin bombardear el guión completo Esperemos que otros encuentren esto útil.

Sería bueno si mysqlsimplemente agregara una opción para suprimir esta advertencia.

tresf
fuente
1

Si utiliza Rundeck para programar sus tareas, o cualquier otra plataforma donde solicite un mylogin.cnfarchivo, he utilizado con éxito el siguiente código de shell para proporcionar una nueva ubicación para el archivo antes de continuar con las llamadas sql:

if test -f "$CUSTOM_MY_LOGINS_FILE_PATH"; then
   chmod 600 $CUSTOM_MY_LOGINS_FILE_PATH
   export MYSQL_TEST_LOGIN_FILE="$CUSTOM_MY_LOGINS_FILE_PATH"
fi

...

result=$(mysql --login-path=production -NBA -D $schema -e "$query")

¿Dónde MYSQL_TEST_LOGIN_FILEestá una variable de entorno que se puede establecer en una ruta de archivo diferente a la predeterminada?

Esto es especialmente útil si está ejecutando un proceso bifurcado y no puede mover o copiar archivos al $HOMEdirectorio.

Ver documentación aquí.

Patrick.SE
fuente
0

la mejor solución es usar alias:

alias [yourapp]-mysql="mysql -u root -psomepassword -P3306 -h 127.0.0.1"

ejemplo, pon esto en tu script:

alias drupal-mysql="mysql -u root -psomepassword -P3306 -h 127.0.0.1"

luego más tarde en su script para cargar una base de datos:

drupal-mysql database_name < database_dump.sql

para ejecutar una declaración:

drupal-mysql -e "EXEC SOMESTATEMENT;"
Neil Davis
fuente
luego unalias the aliaas:
Neil Davis
Para su información, no puede usar alias si está llamando a mysql dentro de una función dentro del script.
user3616725
0

Definir el ayudante:

remove-warning () {
    grep -v 'mysql: [Warning] Using a password on the command line interface can be insecure.'
}

Úselo:

mysql -u $user -p$password -e "statement" 2>&1 | remove-warning

Tachaan! Su código es limpio y agradable de leer.

(probado con bash)

volingas
fuente
-1

Otra solución (de un script, por ejemplo):

 sed -i'' -e "s/password=.*\$/password=$pass/g" ~/.my.cnf
 mysql -h $host -u $user $db_name -e "$sql_cmd"

La -i''opción está aquí para compatibilidad con Mac OS X. Los sistemas operativos UNIX estándar pueden usar directamente-i

Benoit Duffez
fuente
1
la contraseña todavía está en la línea de comando del 'sed', por lo que permanece visible en las listas de procesos, aunque solo sea brevemente.
Anthony
-1

El problema que tuve fue usar la salida en condicional en un script bash.

Esto no es elegante, pero en un entorno de docker esto realmente no debería importar. Básicamente todo lo que hace es ignorar la salida que no está en la última línea. Puede hacer lo mismo con awk, y cambiar para devolver todo excepto la primera línea, etc.

Esto solo devuelve la última línea

mysql -u db_user -pInsecurePassword my_database ... | sed -e '$!d'

No suprimirá el error, pero se asegurará de que pueda usar el resultado de una consulta en un script bash.

WiR3D
fuente
-1

La forma más fácil:

mysql -u root -p YOUR_DATABASE

Ingrese esto y deberá ingresar su contraseña.

Nota: Sí, sin punto y coma.

LukasNiessen
fuente
-3

Puede ejecutar mySQL y suprimir mensajes de advertencia y error utilizando / dev / null, por ejemplo:

# if you run just a SQL-command
mysql -u ${USERNAME} -p${PASSWORD} -h ${HOST} ${DATABASE} -e "${STATEMENT}" &> /dev/null

# Or you can run SQL-script as a file
mysql -u ${USERNAME} -p${PASSWORD} -h ${HOST} ${DATABASE} < ${FILEPATH} &> /dev/null

Dónde:

${USERNAME} - existing mysql user

${PASSWORD} - password

${HOST}     - ip or hostname, for example 'localhost'

${DATABASE} - name of database

${STATEMENT}- SQL command

${FILEPATH} - Path to the SQL-script

¡disfrutar!

Stan Khalipa
fuente
1
Solo tenga en cuenta que suprimirá TODOS los mensajes de error, no solo las advertencias de contraseña.
Simon East
-3

Funcionó para mí: solo lo agregué 2> nulldespués de $(mysql_command), y eliminará solo los mensajes de Errores y Advertencia.

MMG
fuente
1
¡Eso también significa que no recibirá un informe cuando algo más salga mal!
Anthony
Además, probablemente querías 2>/dev/null. El uso 2> nullsolo pondría la salida en un archivo llamado "nulo" en el directorio actual.
thelogix