Wie übergebe ich ein Kennwort an einen untergeordneten Prozess?

18

Das Übergeben eines Kennworts in der Befehlszeile (an einen von meinem Programm aus gestarteten untergeordneten Prozess) ist bekanntermaßen unsicher (da es auch von anderen Benutzern mit dem Befehl ps gesehen werden kann). Ist es in Ordnung, es stattdessen als Umgebungsvariable zu übergeben?

Was kann ich sonst noch verwenden, um es zu bestehen? (Mit Ausnahme der Umgebungsvariablen) Die einfachste Lösung scheint ein Rohr zu verwenden, aber diese einfachste Lösung ist nicht einfach.

Ich programmiere in Perl.

porton
quelle
2
Warum ist es nicht einfach? Es muss keine separate / benannte Pipe sein, nur reguläres stdin / out reicht aus ... das sollte in keiner Sprache zu viel Mühe bereiten. Sie können es in eine einfache Konfigurationsdatei einfügen, wenn Sie sicherstellen möchten, dass es nur von interessierenden Prozessen gelesen werden kann (was viel schwieriger ist, als es sich anhört).
Frostschutz
1
Wenn Sie exec im Kind nicht anrufen, haben Sie immer noch eine Kopie des Passworts, ohne etwas tun zu müssen.
James Youngman

Antworten:

26

Prozessargumente sind für alle Benutzer sichtbar, aber die Umgebung ist nur für denselben Benutzer sichtbar ( zumindest unter Linux , und ich denke bei jeder modernen Unix-Variante). Die Weitergabe eines Kennworts über eine Umgebungsvariable ist daher sicher. Wenn jemand Ihre Umgebungsvariablen lesen kann, kann er Prozesse wie Sie ausführen, sodass das Spiel bereits zu Ende ist.

Es besteht die Gefahr, dass der Inhalt der Umgebung indirekt verloren geht, wenn Sie beispielsweise pseine Untersuchung durchführen und versehentlich das Ergebnis einschließlich vertraulicher Umgebungsvariablen an einem öffentlichen Ort kopieren und einfügen. Ein weiteres Risiko besteht darin, dass Sie die Umgebungsvariable an ein Programm übergeben, das sie nicht benötigt (einschließlich untergeordneter Elemente des Prozesses, für den das Kennwort erforderlich ist), und dass das Programm seine Umgebungsvariablen offenlegt, weil es nicht erwartet hat, dass sie vertraulich sind. Wie hoch diese Risiken für sekundäre Leckagen sind, hängt davon ab, was der Prozess mit dem Kennwort bewirkt (wie lange wird er ausgeführt? Werden Unterprozesse ausgeführt?).

Es ist einfacher sicherzustellen, dass das Kennwort nicht versehentlich durchgesickert ist, indem es durch einen Kanal geleitet wird, der nicht zum Abhören vorgesehen ist, z. B. eine Pipe. Dies ist auf der Senderseite ziemlich einfach zu bewerkstelligen. Wenn Sie beispielsweise das Kennwort in einer Shell-Variablen haben, können Sie dies einfach tun

echo "$password" | theprogram

if theprogramerwartet das Passwort bei seiner Standardeingabe. Beachten Sie, dass dies sicher ist, da echoes sich um eine integrierte Funktion handelt. Mit einem externen Befehl wäre dies nicht sicher, da das Argument in der psAusgabe verfügbar gemacht würde . Ein anderer Weg, um den gleichen Effekt zu erzielen, ist mit einem Here-Dokument:

theprogram <<EOF
$password
EOF

Einige Programme, die ein Kennwort benötigen, können angewiesen werden, es aus einem bestimmten Dateideskriptor zu lesen. Sie können einen anderen Dateideskriptor als die Standardeingabe verwenden, wenn Sie die Standardeingabe für etwas anderes benötigen. Zum Beispiel mit gpg:

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

Wenn das Programm nicht angewiesen werden kann, aus einem Dateideskriptor zu lesen, sondern aus einer Datei, können Sie es anweisen, aus einem Dateideskriptor zu lesen, indem Sie einen Dateinamen wie `/ dev / fd / 3 verwenden.

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

In ksh, bash oder zsh können Sie dies durch Prozessersetzung präziser ausführen.

theprogram --password-from-file=<(echo "$password")
Gilles 'SO - hör auf böse zu sein'
quelle
Unter Solaris 9 und älter /usr/ucb/pswar setuid root so eingestellt, dass Umgebungsvariablen anderer Prozesse gelesen und angezeigt werden konnten - dies wurde in Solaris 10 entfernt, sodass die Antwort "jede andere moderne Unix-Variante" auf Solaris-Releases ab 2005 und höher zutrifft.
Alanc
@alanc Tatsächlich halte ich Solaris <10 heutzutage nicht für modern. Solaris 9 ist fast so alt wie Windows XP!
Gilles 'SO- hör auf böse zu sein'
Gilles: Es gibt Tage, an denen es mir schwerfällt, Solaris 10 modern zu betrachten, seit Solaris 11 mehr als 5 Jahre nicht mehr
verfügbar ist. Daher
10

Anstatt das Kennwort direkt über ein Argument oder eine Umgebungsvariable zu übergeben

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

Verwenden Sie dasselbe Argument oder dieselbe Umgebungsvariable, um einen Dateinamen zu übergeben :

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

Dann können Sie entweder einen Pass Erlaubnis geschützte reguläre Datei (obwohl das schützt Sie nicht von anderen Prozessen unter demselben Benutzer ausgeführt wird ), oder /dev/stdinund Rohr es in (was AFAIK Sie von anderen Prozessen schützen unter dem gleichen Benutzer ausgeführt wird ):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

Wenn Sie /dev/stdinhier verwenden, ist es zwingend erforderlich, dass es eine Pfeife ist . Wenn es sich um ein Terminal handelt, kann es von anderen Prozessen gelesen werden, die unter demselben Benutzer ausgeführt werden.

Wenn Sie Ihre bereits /dev/stdinfür etwas anderes verwenden müssen, können Sie die Prozessersetzung verwenden, wenn Sie sich in einer Shell befinden, die sie unterstützt. Dies entspricht im Wesentlichen der Verwendung von Pipes:

./passwd_receiver <(echo PASSWORD)

Named Pipes (FIFOs) sehen zwar gleich aus, sind aber abfangbar.

Diese Lösungen sind ebenfalls nicht perfekt sicher , aber sie sind möglicherweise eng genug, sofern Sie nicht in einem System mit eingeschränktem Arbeitsspeicher arbeiten, das viel austauscht.

Im Idealfall lesen Sie diese Dateien (Pipe ist auch eine Datei) in den Speicher, der mit mlock (2) als nicht austauschbar markiert ist. Dies ist im Allgemeinen bei Programmen zur Kennwortverarbeitung wie gnupg der Fall.

Anmerkungen:

  1. Das Übergeben von Filedescriptor-Nummern ist theoretisch genauso gut wie das Übergeben von Dateinamen. Dateinamen sind jedoch praktischer, da <()Sie einen Dateinamen und keine Filedescriptor-Nummer erhalten (und coprocSie mit FD_CLOEXEC markierte Filedescriptors erhalten , wodurch diese Filedescriptors in diesem Kontext unbrauchbar werden).

  2. Wenn Sie sich auf einem Linux-System
    /proc/sys/kernel/yama/ptrace_scopebefinden, für das 0AFAIK festgelegt ist, gibt es keine sichere Möglichkeit, sich vor anderen Prozessen zu schützen, die unter demselben Benutzer ausgeführt werden.

  3. Wenn Sie Ihr Kennwort nur von Prozessen fernhalten müssen, die unter anderen (nicht-Stamm-) Benutzern ausgeführt werden, sind Argumente, Umgebungsvariablen, Pipes und durch Berechtigungen geschützte Dateien ausreichend.

PSkocik
quelle
7

Nein, Umgebungsvariablen können auch leicht gelesen werden und gehen an untergeordnete Prozesse verloren. Pass es mit einem Rohr.

Jasen
quelle
2
"Umgebungsvariablen ... lecken zu untergeordneten Prozessen" Das ist der springende Punkt bei der Verwendung einer Umgebungsvariablen. Sie wären nutzlos, wenn sie nicht geerbt würden. "Umgebungsvariablen können auch leicht gelesen werden", nein, das sind sie nicht.
Patrick
2
Lesen Sie die Variable und deaktivieren Sie sie. Es ist nicht schwer. Und Sie könnten das gleiche Argument über die Pipe verwenden. Wenn die Pipe nicht gelesen wird, wird sie an den untergeordneten Prozess übergeben, und der untergeordnete Prozess kann sie lesen und das Kennwort abrufen.
Patrick
1
@Patrick Die dokumentierten mittels Entschärfen Umgebungsvariablen nicht unbedingt den Wert aus der Position schrubben , wo psund /procsie sehen können.
zwol
1
Kann man mit einem System Umgebungsvariablen beliebiger Prozesse lesen? Ich denke nicht, dass Linux es für Prozesse zulässt, die anderen gehören, und wenn Sie derselbe Benutzer sind, können Sie ptrace()trotzdem nur das Ziel und dessen Speicher lesen.
Ilkkachu
5
Diese Antwort ist falsch. Umgebungsvariablen können von anderen Benutzern nicht gelesen werden.
Gilles 'SO- hör auf böse zu sein'
1

Wenn nichts anderes passt, ziehen Sie den Linux Key Retention Service (Kernel-Schlüsselringe) in Betracht.

Beginnen Sie unter: security / keys.txt . Einer der Standardschlüsselringe kann zwischen übergeordneten und untergeordneten Prozessen geklont werden.

Es ist nicht die einfachste Lösung, aber es ist da und scheint gewartet und verwendet zu werden (es war letztes Jahr auch in einem Android-Fehler verwickelt.)

Ich weiß nichts über den "politischen" Status, aber ich hatte ein ähnliches Bedürfnis und fing an, an einer Guile-Bindung zu arbeiten. Bisheriger Perl-Support ist nicht bekannt.

kzurell
quelle