Existe-t-il un moyen de transmettre des données sensibles dans bash en utilisant une invite, pour n’importe quelle commande?

40

Supposons que j'utilisais sha1passpour générer un hachage d'un mot de passe sensible sur la ligne de commande. Je peux utiliser sha1pass mysecretpour générer un hachage de mysecretmais cela a l'inconvénient qui mysecretest maintenant dans l'histoire bash. Existe-t-il un moyen d’atteindre l’objectif final de cette commande tout en évitant de révéler mysecretle texte brut, peut-être en utilisant une passwdinvite -style?

Je suis également intéressé par un moyen généralisé de faire cela pour transmettre des données sensibles à n'importe quelle commande. La méthode changerait lorsque les données sensibles seraient transmises sous forme d'argument (comme dans sha1pass) ou sur STDIN à une commande.

Y a-t-il un moyen d'accomplir cela?


Edit : Cette question a attiré beaucoup d'attention et plusieurs bonnes réponses ont été proposées ci-dessous. Un résumé est:

  • Selon la réponse de @ Kusalananda , idéalement, il ne serait jamais nécessaire de donner un mot de passe ou un secret en tant qu'argument de ligne de commande à un utilitaire. Ceci est vulnérable de plusieurs manières, comme décrit par lui, et on devrait utiliser un utilitaire mieux conçu capable de prendre l'entrée secrète sur STDIN.
  • La réponse de @ vfbsilva explique comment éviter que des éléments ne soient stockés dans l'historique bash
  • La réponse de @ Jonathan décrit une méthode parfaitement efficace pour accomplir cela tant que le programme peut prendre ses données secrètes sur STDIN. En tant que tel, j'ai décidé d'accepter cette réponse. sha1passdans mon OP était juste un exemple, mais la discussion a établi qu'il existe de meilleurs outils qui prennent des données sur STDIN.
  • comme le note @R .. dans sa réponse , l'utilisation de l'extension de commande sur une variable n'est pas sans danger.

En résumé, j’ai accepté la réponse de @ Jonathan car c’est la meilleure solution étant donné que vous disposez d’un programme bien conçu et bien conçu. Bien que le fait de passer un mot de passe ou un secret en tant qu'argument de ligne de commande soit fondamentalement dangereux, les autres réponses permettent d'atténuer les simples problèmes de sécurité.

cemuler
la source
6
De plus, quiconque se trouvant sur le même ordinateur et autorisé à répertorier les processus en cours peut potentiellement voir que celui-ci sha1pass mysecretest en cours d'exécution et donc savoir ce qu'il en mysecretest. (Cela ne fonctionne que pendant quelques secondes lorsque le programme est en cours d'exécution, bien sûr ...)
MathematicalOrchid
@MathematicalOrchid Ceci pourrait être évité en s'exécutant sur une machine virtuelle privée. Mais cela peut être trop de travail à mettre en place pour générer un seul mot de passe ... :-)
Kusalananda
5
@Kusalananda Mon point de vue était plus "ne mettez jamais de données sensibles sur la ligne de commande, même si vous savez comment désactiver l'historique des commandes" ...
MathematicalOrchid
2
Pour votre information, SHA-1 est déconseillé pour les hachages de clés ou de mots de passe depuis quelques années maintenant.
David Foerster
2
Notez que si le système exécute un démon d'audit, toutes les commandes et tous les arguments de tous les utilisateurs sont consignés de manière centralisée par la racine. Ainsi, tous ceux qui peuvent accéder à ces journaux le verront.
Randall

Réponses:

21

Si vous utilisez le shell zshou bash, utilisez l'option -s du readshell intégré pour lire une ligne à partir du terminal sans l'écho.

IFS= read -rs VARIABLE < /dev/tty

Vous pouvez ensuite utiliser une redirection sophistiquée pour utiliser la variable en tant que stdin.

sha1pass <<<"$VARIABLE"

Si quelqu'un court ps, tout ce qu'il verra, c'est "sha1pass".

Cela suppose que sha1passle mot de passe de stdin (sur une ligne, en ignorant le séparateur de ligne) soit lu sans aucun argument.

Jonathan
la source
Je crois que nous avons établi que sha1passn'utilise pas son flux d'entrée standard.
Kusalananda
@Kusalananda D'accord, mais cette méthode fonctionnera pour les programmes qui lisent à partir de stdin.
Jonathan
Donc, en supposant que l’utilitaire puisse prendre son entrée secrète sur STDIN, il s’agit d’une solution saine et sûre sur le plan de la sécurité?
cemulate le
J'ai décidé d'accepter cette réponse, car c'est la meilleure solution étant donné que vous disposez d'un programme bien conçu pour travailler. sha1passétait juste un exemple dans mon OP, et clairement pas le meilleur choix à utiliser pour cela.
cemulate le
1
@cemulate, ... n'est pas sécurisé sur une ligne de commande . Dans le contexte d'un heredoc ou herestring (comme dans la réponse ici), il n'est pas exposé à ps, mais peut être écrit dans un fichier temporaire - si l'on veut éviter cela, alors sshpass < <(printf '%s\n' "$VARIABLE")peut être considéré (parce queprintf que commande externe, il n'est pas passé à execvet accessible via ps).
Charles Duffy
36

Idéalement, vous ne devez jamais taper un mot de passe en texte clair sur la ligne de commande en tant qu'argument d'une commande. Cela fait du mot de passe un argument de la commande et des arguments de ligne de commande peuvent être vus dans la table de processus en utilisant des outils simples tels que psou enregistrés dans certains journaux d'audit.

Cela dit, il existe certainement des moyens de masquer le mot de passe actuel de l'historique des commandes du shell.

sha1pass "$( head -n 1 )"

Tapez ensuite le mot de passe et appuyez sur Enter. La headcommande utilisée ici accepte exactement une ligne d'entrée et la dernière nouvelle ligne que vous tapez ne fera pas partie des données transmises sha1pass.

Pour empêcher les caractères de faire écho:

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

La stty -echocommande désactive l'écho des caractères saisis sur le terminal. L'écho est alors restauré avec stty echo.

Pour transmettre l’entrée standard, cette dernière commande pourrait être modifiée (vous l’auriez fait si sha1passles données acceptées sur l’entrée standard, mais comme si cet utilitaire ignorait son entrée standard):

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

Si vous avez besoin d’une entrée multiligne (ce qui précède suppose qu’une seule ligne doit être passée, sans caractère de nouvelle ligne à la fin), remplacez la headcommande entière par catet terminez l’entrée (en supposant que ce somecommandsoit lu jusqu’à la fin du fichier) par Ctrl+D( suivant Returnsi vous voulez inclure un caractère de nouvelle ligne dans l'entrée, ou deux fois sinon).

Cela fonctionnerait quel que soit le shell que vous utilisiez (à condition qu'il s'agisse d'un shell de type Bourne ou de type rc).

Certains shells peuvent ne pas enregistrer les commandes saisies dans leurs fichiers d’historique si celle-ci est précédée d’un espace. Cela implique généralement de définir HISTCONTROLla valeur ignorespace. Ceci est soutenu par au moinsbash et kshsur OpenBSD, mais pas par exemple par ksh93ou dash. zshles utilisateurs peuvent utiliser l' histignorespaceoption ou leur HISTORY_IGNOREvariable pour définir un modèle à ignorer.

Dans les shells prenant en charge la lecture readsans écho des caractères sur le terminal, vous pouvez également utiliser

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"

mais cela a évidemment toujours le même problème avec la possibilité de révéler le mot de passe dans la table de processus.

Si l'utilitaire lit à partir de l'entrée standard et si le shell prend en charge les "ici-chaînes", ce qui précède peut être remplacé par

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

Résumé des commentaires ci-dessous:

  • L'exécution d'une commande avec un mot de passe indiqué sur la ligne de commande, comme toutes les commandes ci-dessus, à l'exception de celle qui dirige les données vers la commande, rendra potentiellement le mot de passe visible pour tous ceux qui s'exécutent psen même temps. Toutefois, aucune des commandes ci-dessus ne sauvegarde le mot de passe saisi dans le fichier d’historique du shell s’il est exécuté à partir d’un shell interactif.

  • Les programmes bien conçus qui lisent les mots de passe en texte clair le font en lisant depuis leur entrée standard, depuis un fichier ou directement depuis le terminal.

  • sha1pass do requiert le mot de passe sur la ligne de commande, que vous le saisissiez directement ou que vous utilisiez une forme de substitution de commande.

  • Si possible, utilisez un autre outil.

Kusalananda
la source
11
Ceci est une erreur. Le résultat du développement de la commande $(...)fera partie de la ligne de commande et sera visible dans la pssortie, sauf sur un système avec / proc durci.
R ..
3
@Kusalananda, même en écrasant l'argv après le démarrage laisse une fenêtre vulnérable avant que cet écrasement ne se produise; c'est une atténuation, pas une solution.
Charles Duffy
5
@Kusalananda, aucun programme bien conçu pour le hachage des mots de passe ne nécessite une entrée sur la ligne de commande, de sorte que le conditionnel est fondamentalement une donnée. Si ce n'est pas le cas , vous devez choisir un outil différent.
Charles Duffy
4
@ Charles Duffy: L'outil ici semble fondamentalement cassé. sha1passExécuter sans mot de passe sur la ligne de commande semble produire une sortie sans rien lire ... Donc, OP doit choisir un outil différent.
R ..
8
Cette réponse est dangereuse du point de vue de la sécurité et le seul avantage est que le mot de passe n'apparaît pas dans l'historique du shell, mais cet avantage est plus facile à obtenir en incluant un espace devant la commande
Ferrybig le
25

Si vous définissez HISTCONTROLcomme ceci:

HISTCONTROL=ignorespace

et lancez la commande avec un espace:

~$  mycommand

il ne sera pas stocké dans l'historique.

vfbsilva
la source
10

Passer des données sensibles via un tube ou here-doc:

command_with_secret_output | command_with_secret_input

ou:

command_with_secret_input <<EOF
$secret
EOF

Il est normal que des secrets se trouvent dans des variables shell (non exportées), mais vous ne pouvez jamais utiliser ces variables sur des lignes de commande, uniquement dans here-documents et les éléments internes du shell.

Comme l'a noté Kusalananda dans un commentaire, si vous entrez des commandes dans un shell interactif, les lignes que vous entrez pour un document here seront stockées dans l'historique du shell. Il est donc dangereux de taper un mot de passe ici utiliser des variables de shell contenant des secrets en toute sécurité; l'histoire contiendra le texte $secretplutôt que ce que$secret développé.

L'utilisation des extensions de commandes n'est pas sûre :

command_with_secret_input "$(command_with_secret_output)"

parce que la sortie sera incluse dans la ligne de commande et visible dans ps sortie (ou lue manuellement à partir de / proc) sauf sur les systèmes dotés de / proc durci.

L'affectation à une variable est également acceptable:

secret=$(command_with_secret_output)
R ..
la source
Ce que je recherche, c’est une commande réelle command_with_secret_outputqui me permet de taper la sortie secrète. Existe-t-il une telle commande qui pourrait être substituée ici?
cemulate
Notez que la saisie d'un document here dans une bash session interactive enregistre le document dans l'historique.
Kusalananda
@cemulate: utilisez simplement le shell intégré read, par exemple read -r secret. Ensuite, votre secret est dans $secret. Vous pouvez exécuter stty avant / après pour masquer l'entrée si vous le souhaitez.
R ..
3
@Kusalananda: sha1passsemble fondamentalement cassé / inutilisable / dangereux car il ne peut pas lire le mot de passe de stdin ou d'un fichier. Je pense qu’il faut un utilitaire différent pour résoudre le problème.
R ..
1
@cemulate Votre dernier commentaire à R est exactement sur place. C'est pourquoi ça ne va pas aider. read -rsfera le travail (si vous incluez -rpour pouvoir avoir des mots de passe avec des barres obliques inverses), mais alors vous êtes de nouveau en train de montrer le mot de passe dans la liste de processus (et selon que la comptabilité de processus est activée et comment elle est configurée , dans les journaux de comptabilisation des processus également).
Kusalananda
6

Il suffit d'écrire la valeur dans un fichier et de le transmettre:

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

Je ne sais pas comment ça sha1passmarche, si vous pouvez utiliser un fichier en entrée, vous pouvez l'utiliser sha1pass < mysecret. Sinon, utiliser catpeut être un problème car il inclut la nouvelle ligne finale. Si c'est le cas, utilisez (si vos headsupports -c):

head -c-1 mysecret | sha1pass 
terdon
la source
2
Pourquoi écrire le mot de passe sur le disque dans votre premier exemple alors que vous pouvez simplement le faire cat | sha1pass? cat mysecret | sha1passet sha1pass < mysecretavoir le même comportement vis-à-vis des nouvelles lignes finales. catn'ajoute pas de nouvelles lignes. Quoi qu'il en soit, si sha1passsupporte le passage du mot de passe via une entrée standard, je m'attendrais à ce qu'il ignore la nouvelle ligne finale par lui-même. Les fichiers avec des lignes qui ne sont pas terminées par des retours à la ligne ne sont pas naturels sous Unix, alors il serait difficile de s’attendre à ce qu’un fichier ne se termine pas par un retour à la ligne.
JoL
@JoL i) parce que je n'y avais pas pensé: / Mais comment cela fonctionnerait-il? cat | sha1passsemble courir sha1passavant de me donner une chance d'entrer n'importe quelle entrée. ii) Non, bien sûr, cat mysecretn'ajoute pas de nouvelle ligne, je n'ai jamais dit de l' catajouter, seulement qu'elle l' inclue .
terdon
Je vois, mais ce n'est pas comme si l' < mysecretenlève non plus. :)
JoL
Ça ne fait rien. Maintenant que je relis, je vois que vous avez dit cela pour proposer plus tard head -c-1. Je suppose que je viens de me demander pourquoi utiliser cat mysecret | sha1passet ensuite proposer sha1pass < mysecret. Je suppose que l'inquiétude est que sha1pass pourrait se plaindre de fichiers standard pour stdin; Je ne sais pas pourquoi.
JoL
@JoL, c’est plus parce que je n’ai jamais utilisé sha1passet n’ai trouvé aucun manuel ni -haucune autre forme de documentation au cours des quelques minutes que j’ai passées à chercher et que je ne pouvais donc pas savoir si son exécution était sha1pass footraitée foocomme une chaîne de saisie ou comme un fichier d’entrée . J'ai donc donné des options pour traiter chaque possibilité.
terdon
1

Si ce que terdon a fait est possible, alors c'est la meilleure solution, en passant par l'entrée standard. Le seul problème est qu'il a écrit le mot de passe sur le disque. Nous pouvons le faire à la place:

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

Comme dit Kusalananda, stty -echoveille à ce que ce que vous tapez ne soit pas vu avant de le stty echorefaire. head -1obtiendra une ligne de l’entrée standard et la transmettra à sha1pass.

JoL
la source
0

j'utiliserais

sha1pass "$(cat)"

catlirait de stdin jusqu’à EOF, ce qui peut être provoqué en appuyant sur Ctrl + D. Ensuite, le résultat serait passé comme argument àsha1pass

oktupol
la source
3
La réponse de R .. explique pourquoi c'est dangereux.
hvd