¿Hay alguna manera de pasar datos confidenciales en bash usando un indicador, para cualquier comando?

40

Supongamos que estaba usando sha1passpara generar un hash de alguna contraseña sensible en la línea de comando. Puedo usar sha1pass mysecretpara generar un hash de mysecretpero esto tiene la desventaja que mysecretahora está en el historial de bash. ¿Hay alguna manera de lograr el objetivo final de este comando mientras se evita revelar mysecreten texto plano, tal vez utilizando un passwdindicador de estilo?

También estoy interesado en una forma generalizada de hacer esto para pasar datos confidenciales a cualquier comando. El método cambiaría cuando los datos confidenciales se pasan como un argumento (como en sha1pass) o en STDIN a algún comando.

¿Hay alguna manera de lograr esto?


Editar : Esta pregunta atrajo mucha atención y se han ofrecido varias buenas respuestas a continuación. Un resumen es:

  • Según la respuesta de @ Kusalananda , idealmente uno nunca tendría que dar una contraseña o secreto como argumento de línea de comandos a una utilidad. Esto es vulnerable de varias maneras según lo descrito por él, y uno debería usar una utilidad mejor diseñada que sea capaz de tomar la entrada secreta en STDIN
  • La respuesta de @ vfbsilva describe cómo evitar que las cosas se almacenen en el historial de bash
  • La respuesta de @ Jonathan describe un método perfectamente bueno para lograr esto siempre que el programa pueda tomar sus datos secretos en STDIN. Como tal, he decidido aceptar esta respuesta. sha1passen mi OP fue solo un ejemplo, pero la discusión ha establecido que existen mejores herramientas que toman datos sobre STDIN.
  • Como @R .. señala en su respuesta , el uso de la expansión de comandos en una variable no es seguro.

En resumen, acepté la respuesta de @ Jonathan ya que es la mejor solución dado que tiene un programa bien diseñado y con buen comportamiento para trabajar. Aunque pasar una contraseña o un secreto como argumento de la línea de comandos es fundamentalmente inseguro, las otras respuestas proporcionan formas de mitigar las preocupaciones simples de seguridad.

cemulate
fuente
66
No solo eso: cualquier persona en la misma máquina con permiso para enumerar procesos en ejecución puede ver potencialmente que se sha1pass mysecretestá ejecutando y, por lo tanto, saber qué mysecretes. (Esto solo funciona durante unos segundos mientras el programa se está ejecutando, por supuesto ...)
MathematicalOrchid
@MathematicalOrchid Esto podría evitarse ejecutando en una máquina virtual privada. Pero puede ser demasiado trabajo configurar para generar una sola contraseña ... :-)
Kusalananda
55
@Kusalananda Mi punto era más "nunca pongas datos confidenciales en la línea de comandos, incluso si descubres cómo desactivar el historial de comandos" ...
MathematicalOrchid
2
Para que lo sepas, SHA-1 está en desuso para los hash de clave o contraseña desde hace bastantes años.
David Foerster el
2
Tenga en cuenta que si el sistema ejecuta un daemon de auditoría, todos los comandos y todos los argumentos de todos los usuarios se registran de forma centralizada por root, por lo que cualquier persona que pueda acceder a esos registros lo verá.
Randall

Respuestas:

21

Si usa el shell zsho bash, use la opción -s en el readshell incorporado para leer una línea del dispositivo terminal sin que se repita.

IFS= read -rs VARIABLE < /dev/tty

Luego puede usar una redirección elegante para usar la variable como stdin.

sha1pass <<<"$VARIABLE"

Si alguien corre ps, todo lo que verá es "sha1pass".

Eso supone que sha1passlee la contraseña de stdin (en una línea, ignorando el delimitador de línea) cuando no se le da ningún argumento.

Jonathan
fuente
Creo que establecimos que sha1passno utiliza su flujo de entrada estándar.
Kusalananda
@Kusalananda Está bien, pero este método funcionará para programas que sí leen desde stdin.
Jonathan
Entonces, suponiendo que la utilidad pueda tomar su entrada secreta en STDIN, esta es una solución segura y segura, ¿en términos de seguridad?
cemulate
He decidido aceptar esta respuesta, dado que es la mejor solución dado que tiene un programa bien diseñado para trabajar. sha1passfue solo un ejemplo en mi OP, y claramente no es la mejor opción para esto.
cemulate
1
@cemulate, ... no es seguro en una línea de comando . En el contexto de un heredoc o herestring (como en la respuesta aquí), no está expuesto a ps, pero puede escribirse en un archivo temporal; si uno quiere evitar eso, entonces sshpass < <(printf '%s\n' "$VARIABLE")podría considerarse (porque printfes un incorporado, no un comando externo, no se pasa execvy no se puede acceder a través de ps).
Charles Duffy el
36

Idealmente, nunca escriba una contraseña de texto sin cifrar en la línea de comando como argumento para un comando. Al hacerlo, la contraseña se convierte en un argumento para el comando, y los argumentos de la línea de comando se pueden ver en la tabla de procesos mediante el uso de herramientas simples como pso iniciar sesión en algunos registros de auditoría.

Dicho esto, ciertamente hay formas de ocultar la contraseña real del historial de comandos del shell.

sha1pass "$( head -n 1 )"

Luego ingrese la contraseña y presione Enter. El headcomando utilizado aquí acepta exactamente una línea de entrada y la última línea nueva que escriba no formará parte de los datos a los que se pasa sha1pass.

Para evitar que los caracteres hagan eco:

sha1pass "$( stty -echo; head -n 1; stty echo )"

El stty -echocomando desactiva el eco de los caracteres escritos en el terminal. El eco se restaura con stty echo.

Para pasar la entrada estándar, ese último comando podría modificarse (lo habría hecho si hubiera sha1passaceptado los datos en la entrada estándar, pero parece que esta utilidad en particular está ignorando su entrada estándar):

{ stty -echo; head -n 1; stty echo; } | somecommand

Si necesita una entrada de varias líneas (lo anterior supone que se debe pasar una sola línea, sin caracteres de nueva línea al final), reemplace todo el headcomando con caty termine la entrada (suponiendo que somecommandse lea hasta el final del archivo) con Ctrl+D( siguiente Returnsi desea incluir un carácter de nueva línea en la entrada, o dos veces si no).

Esto funcionaría independientemente de qué shell estuviera utilizando (siempre que fuera un shell tipo Bourne o rc).

Se pueden hacer algunos shells para no guardar los comandos escritos en sus archivos de historial si el comando está precedido por un espacio. Esto generalmente implica tener que establecer HISTCONTROLel valor ignorespace. Esto es apoyado por al menos bashy kshen OpenBSD, pero no por ejemplo ksh93o dash. zshlos usuarios pueden usar la histignorespaceopción o su HISTORY_IGNOREvariable para definir un patrón a ignorar.

En los shells que admiten la lectura con readcaracteres sin eco en el terminal, también puede usar

IFS= read -rs password     # -s turns off echoing in bash or zsh
                           # -r for reading backslashes as-is,
                           # IFS= to preserve leading and trailing blanks
sha1pass "$password"

pero esto obviamente todavía tiene el mismo problema al revelar potencialmente la contraseña en la tabla de procesos.

Si la utilidad lee de la entrada estándar y el shell admite "here-strings", lo anterior podría cambiarse a

IFS= read -rs password
somecommand <<<"$password"

Resumen de comentarios a continuación:

  • Ejecutar un comando con una contraseña dada en la línea de comando, lo que hace todos los comandos anteriores, excepto el que canaliza los datos al comando, hará que la contraseña sea visible para cualquiera que se ejecute psal mismo tiempo. Sin embargo, ninguno de los comandos anteriores guardará la contraseña ingresada en el archivo de historial del shell si se ejecuta desde un shell interactivo.

  • Los programas que se comportan bien y que leen contraseñas de texto sin cifrar lo hacen leyendo desde su entrada estándar, desde un archivo o directamente desde el terminal.

  • sha1pass requiere la contraseña en la línea de comando, ya sea ingresada directamente o usando alguna forma de sustitución de comando.

  • Si es posible, use otra herramienta.

Kusalananda
fuente
11
Esto es incorrecto. El resultado de la expansión del comando $(...)será parte de la línea de comando y será visible en la pssalida, excepto en un sistema con hard / proc.
R ..
3
@Kusalananda, incluso sobrescribir el argumento después de comenzar deja una ventana vulnerable antes de que tenga lugar la sobrescritura; Es una mitigación, no una solución.
Charles Duffy el
55
@Kusalananda, ningún programa bien diseñado para contraseñas hash requerirá entrada en la línea de comando, por lo que el condicional es básicamente un hecho; si no lo es , uno debería elegir una herramienta diferente.
Charles Duffy el
44
@CharlesDuffy: la herramienta aquí parece fundamentalmente rota. sha1passejecutar sin contraseña en la línea de comando parece producir una salida sin leer nada ... Por lo tanto, OP debe elegir una herramienta diferente.
R ..
8
Esta respuesta es insegura desde una perspectiva de seguridad, y la única ventaja es que la contraseña no aparece en el historial del shell, pero esa ventaja es más fácil de lograr al incluir un espacio delante del comando
Ferrybig
25

Si configuras HISTCONTROLasí:

HISTCONTROL=ignorespace

e inicie el comando con un espacio:

~$  mycommand

No se almacenará en el historial.

vfbsilva
fuente
10

Pase datos confidenciales a través de una tubería o here-doc:

command_with_secret_output | command_with_secret_input

o:

command_with_secret_input <<EOF
$secret
EOF

Está bien que los secretos estén en variables de shell (no exportadas), pero nunca puede usar esas variables en líneas de comando, solo en documentos aquí y componentes internos de shell.

Como señaló Kusalananda en un comentario, si está ingresando comandos en un shell interactivo, las líneas que ingrese para un documento aquí se almacenarán en el historial del shell, por lo que no es seguro escribir una contraseña allí, pero aún así debería estar seguro para usar variables de shell que contienen secretos; el historial contendrá el texto en $secretlugar de lo que se haya $secretexpandido.

El uso de expansiones de comandos no es seguro :

command_with_secret_input "$(command_with_secret_output)"

porque la salida se incluirá en la línea de comando y será visible en la pssalida (o lectura manual desde / proc) excepto en sistemas con endurecido / proc.

La asignación a una variable también está bien:

secret=$(command_with_secret_output)
R ..
fuente
Lo que estoy buscando es un comando real command_with_secret_outputque me permita escribir la salida secreta. ¿Existe tal comando que pueda ser sustituido aquí?
cemulate
Tenga en cuenta que escribir un documento aquí en una bash sesión interactiva guardará el documento en el archivo de historial.
Kusalananda
@cemulate: solo use el shell incorporado read, por ejemplo read -r secret. Entonces tu secreto está adentro $secret. Puede ejecutar stty antes / después para ocultar la entrada si lo desea.
R ..
3
@Kusalananda: sha1passparece fundamentalmente roto / inutilizable / inseguro ya que no puede leer la contraseña de stdin o un archivo. Creo que se necesita una utilidad diferente para resolver el problema.
R ..
1
@cemulate Su último comentario a R está exactamente en el lugar. Por eso no ayudará. read -rshará el trabajo (si incluye -rpoder tener contraseñas con barras diagonales invertidas), pero luego puede volver a mostrar la contraseña en la lista de procesos (y dependiendo de si la contabilidad de procesos está activada y cómo está configurada) , en el proceso también registros de contabilidad).
Kusalananda
6

Simplemente escriba el valor en un archivo y pase el archivo:

$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass 

No estoy seguro de cómo sha1passfunciona, si puede tomar un archivo como entrada, puede usarlo sha1pass < mysecret. Si no, el uso catpodría ser un problema ya que incluye la nueva línea final. Si ese es el caso, use (si es headcompatible -c):

head -c-1 mysecret | sha1pass 
terdon
fuente
2
¿Por qué escribir la contraseña en el disco en su primer ejemplo cuando puede hacerlo cat | sha1pass? cat mysecret | sha1passy sha1pass < mysecrettener el mismo comportamiento con respecto a las nuevas líneas finales. catno agrega nuevas líneas. De todos modos, si sha1passadmite pasar la contraseña a través de la entrada estándar, esperaría que ignore la nueva línea final por sí misma. Los archivos con líneas que no terminan con nuevas líneas no son naturales en Unix después de todo, por lo que sería incómodo esperar un archivo que no termina con una nueva línea.
JoL
@JoL i) porque no había pensado en eso: / ¿Pero cómo funcionaría eso? cat | sha1passparece correr sha1passantes de darme la oportunidad de ingresar cualquier entrada. ii) No, por supuesto cat mysecret, no agrega una nueva línea, nunca dije que la catagregue, solo que la incluye .
terdon
Ya veo, pero tampoco es como si lo < mysecreteliminara. :)
JoL
No importa. Ahora que lo releí, veo que dijiste eso para luego proponerlo head -c-1. Supongo que me confundí en cuanto a por qué usar cat mysecret | sha1passy luego proponer sha1pass < mysecret. Supongo que la preocupación es que sha1pass podría quejarse de los archivos regulares para stdin; No estoy seguro de por qué.
JoL
@JoL es más porque nunca he usado sha1passy no pude encontrar un manual o -hcualquier otra forma de documentación en los pocos minutos que pasé buscando y, por lo tanto, no pude averiguar si se ejecuta sha1pass footratado foocomo una cadena de entrada o como un archivo de entrada . Por lo tanto, di opciones para lidiar con cada posibilidad.
terdon
1

Si lo que hizo terdon es posible, entonces esa es la mejor solución, pasando por la entrada estándar. El único problema que queda es que escribió la contraseña en el disco. Podemos hacer esto en su lugar:

stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo

Como dijo Kusalananda, stty -echoasegura que lo que escribes no se vea hasta que lo vuelvas a hacer stty echo. head -1obtendrá una línea de entrada estándar y la pasará a sha1pass.

JoL
fuente
0

yo usaría

sha1pass "$(cat)"

catleería desde stdin hasta EOF, que puede ser causado presionando Ctrl + D. Luego, el resultado se pasaría como argumento asha1pass

oktupol
fuente
3
La respuesta de R .. explica por qué esto no es seguro.
hvd