Gibt es eine Möglichkeit, vertrauliche Daten in bash mit einer Eingabeaufforderung für einen Befehl weiterzuleiten?

40

Angenommen, ich habe sha1passeinen Hash eines vertraulichen Kennworts in der Befehlszeile generiert. Ich kann verwenden sha1pass mysecret, um einen Hash zu generieren, mysecretaber das hat den Nachteil, dass mysecretes jetzt in der Bash-Geschichte ist. Gibt es eine Möglichkeit, das Endziel dieses Befehls zu erreichen, ohne dass dies mysecretim Klartext passwdangezeigt wird, z. B. mithilfe einer Eingabeaufforderung im -Stil?

Ich bin auch an einer verallgemeinerten Methode interessiert, um vertrauliche Daten an einen Befehl weiterzuleiten. Die Methode würde sich ändern, wenn die vertraulichen Daten als Argument (z. B. in sha1pass) oder in STDIN an einen Befehl übergeben werden.

Gibt es eine Möglichkeit, dies zu erreichen?


Bearbeiten : Diese Frage hat viel Aufmerksamkeit erregt und es wurden einige gute Antworten unten angeboten. Eine Zusammenfassung ist:

  • Wie pro @ Kusalananda Antwort , im Idealfall würde man nie ein Passwort oder Geheim als Befehlszeilenargument zu einem Dienstprogramm geben muß. Dies ist in mehrfacher Hinsicht verwundbar, wie von ihm beschrieben, und man sollte ein besser gestaltetes Dienstprogramm verwenden, das in der Lage ist, die geheimen Eingaben auf STDIN zu übernehmen
  • @ vfbsilvas Antwort beschreibt, wie Sie verhindern, dass Dinge im Bash-Verlauf gespeichert werden
  • @ Jonathans Antwort beschreibt eine vollkommen gute Methode, um dies zu erreichen, solange das Programm seine geheimen Daten auf STDIN übertragen kann. Aus diesem Grund habe ich mich entschlossen, diese Antwort zu akzeptieren. sha1passIn meinem OP war dies nur ein Beispiel, aber die Diskussion hat ergeben, dass es bessere Tools gibt, die Daten zu STDIN aufnehmen.
  • Wie @R .. in seiner Antwort feststellt , ist die Verwendung der Befehlserweiterung für eine Variable nicht sicher.

Zusammenfassend habe ich @ Jonathans Antwort akzeptiert , da es die beste Lösung ist, vorausgesetzt, Sie haben ein gut gestaltetes und ansprechendes Programm, mit dem Sie arbeiten können. Die Übergabe eines Kennworts oder eines Geheimnisses als Befehlszeilenargument ist zwar grundsätzlich unsicher, die anderen Antworten bieten jedoch Möglichkeiten, um die einfachen Sicherheitsbedenken abzumildern.

cemulieren
quelle
6
Nicht nur das: Jeder auf demselben Computer, der die Berechtigung hat, laufende Prozesse aufzulisten, kann möglicherweise sehen, dass diese sha1pass mysecretausgeführt werden, und somit wissen, was mysecretist. (Dies funktioniert natürlich nur für einige Sekunden, während das Programm ausgeführt wird ...)
MathematicalOrchid
@MathematicalOrchid Dies kann vermieden werden, indem Sie eine private virtuelle Maschine verwenden. Aber das kann zu viel Arbeit sein, um nur ein einziges Passwort zu generieren ... :-)
Kusalananda
5
@Kusalananda Mein Punkt war mehr "Setzen Sie niemals vertrauliche Daten auf die Befehlszeile, auch wenn Sie herausfinden, wie Sie den Befehlsverlauf deaktivieren" ...
MathematicalOrchid
2
Nur damit Sie wissen, ist SHA-1 seit einigen Jahren wegen Schlüssel- oder Passwort-Hashes veraltet.
David Foerster
2
Beachten Sie, dass, wenn das System einen Überwachungsdämon ausführt, alle Befehle und alle Argumente aller Benutzer zentral von root protokolliert werden, sodass jeder, der auf diese Protokolle zugreifen kann, dies sieht.
Randall

Antworten:

20

Wenn Sie die Shell zshoder verwenden bash, verwenden Sie die Option -s für die integrierte readShell, um eine Zeile vom Endgerät zu lesen, ohne dass sie wiederholt wird.

IFS= read -rs VARIABLE < /dev/tty

Dann können Sie eine ausgefallene Umleitung verwenden, um die Variable als stdin zu verwenden.

sha1pass <<<"$VARIABLE"

Wenn jemand rennt ps, wird er nur "sha1pass" sehen.

Dies setzt voraus, dass sha1passdas Kennwort von stdin gelesen wird (in einer Zeile, wobei das Zeilentrennzeichen ignoriert wird), wenn kein Argument angegeben wird.

Jonathan
quelle
Ich glaube, dass wir festgestellt haben, dass sha1passder Standardeingabestrom nicht verwendet wird.
Kusalananda
@Kusalananda Okay, aber diese Methode funktioniert für Programme, die von stdin lesen.
Jonathan
Unter der Annahme, dass das Dienstprogramm seine geheimen Eingaben in STDIN übernehmen kann, ist dies eine sichere und sichere Lösung, was die Sicherheit anbelangt?
Cemulate
Ich habe beschlossen, diese Antwort zu akzeptieren, da dies die beste Lösung ist , wenn Sie ein gut gestaltetes Programm haben, mit dem Sie arbeiten können. sha1passwar nur ein Beispiel in meinem OP und eindeutig nicht die beste Wahl dafür.
Cemulate
1
@cemulate, ... in einer Befehlszeile nicht sicher . Im Rahmen eines heredoc oder herestring (wie in der Antwort hier), es ist nicht ausgesetzt ps, sondern kann in eine temporäre Datei geschrieben werden - wenn man das vermeiden will, dann in sshpass < <(printf '%s\n' "$VARIABLE")Betracht gezogen werden könnte (da printfist ein builtin, kein externer Befehl, der nicht an) weitergegeben wird execvund über diesen erreichbar ist ps.
Charles Duffy
35

Im Idealfall geben Sie niemals ein Klartextkennwort in der Befehlszeile als Argument für einen Befehl ein. Dadurch wird das Kennwort zu einem Argument für den Befehl, und Befehlszeilenargumente können in der Prozesstabelle angezeigt werden, indem einfache Tools verwendet werden, psdie in einigen Überwachungsprotokollen verwendet werden.

Allerdings gibt es durchaus Möglichkeiten, das eigentliche Passwort aus dem Befehlsverlauf der Shell zu entfernen.

sha1pass "$( head -n 1 )"

Geben Sie dann das Passwort ein und drücken Sie Enter. Der headhier verwendete Befehl akzeptiert genau eine Eingabezeile, und die letzte eingegebene neue Zeile ist nicht Teil der Daten, an die übergeben wird sha1pass.

So verhindern Sie das Echo der Zeichen:

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

Der stty -echoBefehl deaktiviert das Echo der eingegebenen Zeichen auf dem Terminal. Das Echo wird dann mit wiederhergestellt stty echo.

Um die Standardeingabe weiterzugeben, könnte der letzte Befehl geändert werden (dies wäre geschehen, wenn sha1passDaten für die Standardeingabe akzeptiert worden wären , es scheint jedoch, als würde dieses Dienstprogramm die Standardeingabe ignorieren):

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

Wenn Sie eine mehrzeilige Eingabe benötigen (in den obigen Abschnitten wird davon ausgegangen, dass eine einzelne Zeile ohne Zeilenumbruchzeichen am Ende übergeben werden soll), ersetzen Sie den gesamten headBefehl durch catund beenden Sie die Eingabe (vorausgesetzt somecommand, sie liest sich bis zum Ende der Datei) mit Ctrl+D( folgenden, Returnwenn Sie ein Zeilenumbruchzeichen in die Eingabe aufnehmen möchten, oder zweimal, wenn nicht).

Dies funktioniert unabhängig davon, welche Shell Sie verwenden (sofern es sich um eine Bourne-ähnliche oder eine RC-ähnliche Shell handelt).

Bei einigen Shells kann es vorkommen, dass die eingegebenen Befehle nicht in ihren Verlaufsdateien gespeichert werden, wenn vor dem Befehl ein Leerzeichen steht. In der Regel muss hierfür HISTCONTROLder Wert eingestellt werden ignorespace. Dies wird von mindestens bashund kshunter OpenBSD unterstützt, aber nicht von zB ksh93oder dash. zshBenutzer können die histignorespaceOption oder ihre HISTORY_IGNOREVariable verwenden, um ein zu ignorierendes Muster zu definieren.

In Shells, die das Lesen mit unterstützen, readohne Zeichen an das Terminal zu senden, können Sie auch verwenden

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"

Dies hat jedoch offensichtlich immer noch das gleiche Problem mit der potenziellen Offenlegung des Kennworts in der Prozesstabelle.

Wenn das Dienstprogramm von der Standardeingabe liest und die Shell "here-strings" unterstützt, kann das oben Gesagte in geändert werden

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

Zusammenfassung der Kommentare unten:

  • Wenn Sie einen Befehl mit einem in der Befehlszeile angegebenen Kennwort ausführen, was bei allen oben genannten Befehlen mit Ausnahme des Befehls, der die Daten an den Befehl weiterleitet, der Fall ist, wird das Kennwort möglicherweise für alle Benutzer sichtbar, psdie gleichzeitig ausgeführt werden. Keiner der obigen Befehle speichert jedoch das eingegebene Kennwort in der Verlaufsdatei der Shell, wenn es von einer interaktiven Shell ausgeführt wird.

  • Gut erzogene Programme, die Klartext-Passwörter lesen, lesen dies von ihrer Standardeingabe, aus einer Datei oder direkt vom Terminal.

  • sha1pass Dies erfordert das Kennwort in der Befehlszeile, das entweder direkt eingegeben oder durch eine Form der Befehlsersetzung ersetzt wird.

  • Verwenden Sie nach Möglichkeit ein anderes Werkzeug.

Kusalananda
quelle
11
Das ist falsch. Das Ergebnis der Befehlserweiterung $(...)ist Teil der Befehlszeile und in der psAusgabe sichtbar, außer auf einem System mit hard / proc.
R ..
3
@Kusalananda, sogar das Überschreiben des Argv nach dem Start hinterlässt ein anfälliges Fenster, bevor das Überschreiben stattfindet. Es ist eine Milderung, keine Lösung.
Charles Duffy
5
@Kusalananda, kein gut gestaltetes Programm zum Hashing von Passwörtern erfordert eine Eingabe über die Befehlszeile, sodass eine Bedingung grundsätzlich gegeben ist. Wenn dies nicht der Fall ist, sollte ein anderes Tool ausgewählt werden.
Charles Duffy
4
@CharlesDuffy: Das Tool hier scheint grundsätzlich kaputt zu sein. sha1passrun with no password on the command line scheint eine Ausgabe zu erzeugen, ohne etwas zu lesen ... OP muss also ein anderes Tool auswählen.
R ..
8
Diese Antwort ist aus Sicherheitsgründen nicht sicher, und der einzige Vorteil besteht darin, dass das Kennwort nicht im Shell-Verlauf
angezeigt wird. Dieser
25

Wenn Sie so einstellen HISTCONTROL:

HISTCONTROL=ignorespace

und starte den Befehl mit einem Leerzeichen:

~$  mycommand

es wird nicht im Verlauf gespeichert.

vfbsilva
quelle
10

Übergeben Sie sensible Daten über eine Pipe oder Here-Doc:

command_with_secret_output | command_with_secret_input

oder:

command_with_secret_input <<EOF
$secret
EOF

Es ist in Ordnung, dass sich Geheimnisse in (nicht exportierten) Shell-Variablen befinden, aber Sie können diese Variablen niemals in Befehlszeilen verwenden, nur in Here-Dokumenten und Shell-Interna.

Wie Kusalananda in einem Kommentar angemerkt hat, werden die Zeilen, die Sie für ein Here-Dokument eingeben, im Shell-Verlauf gespeichert, wenn Sie Befehle in eine interaktive Shell eingeben. Es ist also nicht sicher, dort ein Kennwort einzugeben, es sollte jedoch immer noch so sein sichere Verwendung von Shell-Variablen, die Geheimnisse enthalten; Der Verlauf enthält den Text $secretund nicht das, worauf er $secreterweitert wurde.

Die Verwendung von Befehlserweiterungen ist nicht sicher :

command_with_secret_input "$(command_with_secret_output)"

da die Ausgabe in der Befehlszeile enthalten und in der psAusgabe sichtbar ist (oder manuell aus / proc liest), außer auf Systemen mit gehärtetem / proc.

Die Zuweisung zu einer Variablen ist auch in Ordnung:

secret=$(command_with_secret_output)
R ..
quelle
Was ich suche ist ein tatsächlicher Befehl command_with_secret_output, den ich erlaubt , gibt Sie den geheimen Ausgang. Gibt es einen solchen Befehl, der hier ersetzt werden könnte?
Cemulate
Beachten Sie, dass durch die Eingabe eines Here-Dokuments in einer interaktiven bash Sitzung das Dokument in der Verlaufsdatei gespeichert wird.
Kusalananda
@cemulate: Verwenden Sie einfach die eingebaute Shell read, z read -r secret. Dann ist dein Geheimnis in $secret. Sie können stty davor / danach ausführen, um die Eingabe auszublenden, wenn Sie möchten.
R ..
3
@Kusalananda: Scheint sha1passgrundsätzlich kaputt / unbrauchbar / unsicher zu sein, da es das Passwort von stdin oder einer Datei nicht lesen kann. Ich denke, es wird ein anderes Dienstprogramm benötigt, um das Problem zu lösen.
R ..
1
@cemulate Dein letzter Kommentar zu R ist genau richtig. Deshalb hilft es nicht. read -rserledigt die Aufgabe (wenn Sie -rKennwörter mit umgekehrten Schrägstrichen verwenden möchten), aber dann können Sie das Kennwort möglicherweise wieder in der Prozessliste anzeigen (und dies hängt davon ab, ob die Prozessabrechnung aktiviert und wie konfiguriert ist) , auch in den Prozessabrechnungsprotokollen).
Kusalananda
6

Schreiben Sie einfach den Wert in eine Datei und übergeben Sie die Datei:

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

Ich bin mir nicht sicher, wie es sha1passfunktioniert, wenn es eine Datei als Eingabe nehmen kann, die Sie verwenden können sha1pass < mysecret. Wenn nicht, ist die Verwendung catmöglicherweise ein Problem, da sie die letzte Zeile enthält. Wenn dies der Fall ist, verwenden Sie (wenn Ihre headUnterstützung -c):

head -c-1 mysecret | sha1pass 
terdon
quelle
2
Warum sollten Sie in Ihrem ersten Beispiel das Kennwort auf die Festplatte schreiben, wenn Sie dies nur können cat | sha1pass? cat mysecret | sha1passund sha1pass < mysecrethaben das gleiche Verhalten in Bezug auf endgültige Zeilenumbrüche. catfügt keine Zeilenumbrüche hinzu. Wenn sha1passdie Weitergabe des Kennworts über die Standardeingabe unterstützt wird, würde ich davon ausgehen, dass die letzte Zeile für sich ignoriert wird. Dateien mit Zeilen, die nicht durch Zeilenumbrüche abgeschlossen werden, sind in Unix schließlich unnatürlich. Es wäre daher umständlich, eine Datei zu erwarten, die nicht durch Zeilenumbrüche abgeschlossen wird.
JoL
@ JoL i) weil ich nicht daran gedacht hatte: / Aber wie würde das funktionieren? cat | sha1passscheint zu rennen, sha1passbevor ich die Möglichkeit habe, Eingaben zu machen. ii) Nein, natürlich cat mysecretwird keine neue Zeile hinzugefügt, ich habe nie gesagt cat, dass sie hinzugefügt wird , nur, dass sie diese enthält .
Terdon
Ich verstehe, aber es ist auch nicht so, als würde man es < mysecretentfernen. :)
JoL
Keine Ursache. Jetzt, wo ich es noch einmal lese, sehe ich, dass Sie das gesagt haben, um es später vorzuschlagen head -c-1. Ich schätze, ich war nur verwirrt, warum ich es benutze cat mysecret | sha1passund schlage es später vor sha1pass < mysecret. Ich denke, die Sorge ist, dass sha1pass sich über reguläre Dateien für stdin beschweren könnte; Ich bin mir nicht sicher warum.
JoL
@JoL es ist mehr , weil ich nie benutzt habe sha1passund eine manuelle oder nicht finden konnte , -hoder jede andere Form der Dokumentation in den wenigen Minuten , die ich verbrachte die Suche und so konnte nicht herausfinden , ob Laufen sha1pass foobehandelt fooals Input - String oder als Eingabedatei . Ich gab daher Optionen, um mit jeder Möglichkeit umzugehen.
Terdon
1

Wenn das, was terdon getan hat, möglich ist, dann ist das die beste Lösung, indem es die Standardeingabe durchläuft. Das einzige Problem ist, dass er das Passwort auf die Festplatte geschrieben hat. Wir können dies stattdessen tun:

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

Wie Kusalananda sagte, stty -echostellt sicher, dass das, was Sie eingeben, erst stty echowieder angezeigt wird, wenn Sie es erneut tun . head -1erhält eine Zeile von der Standardeingabe und leitet sie an weiter sha1pass.

JoL
quelle
0

ich würde ... benutzen

sha1pass "$(cat)"

catwürde von stdin bis lesen EOF, was durch Drücken von Strg + D verursacht werden kann. Dann würde das Ergebnis als Argument an übergebensha1pass

oktupol
quelle
3
Die Antwort von R .. erklärt, warum dies unsicher ist.
HDV