Das Szenario:
In einem Bash-Skript muss ich überprüfen, ob ein von einem Benutzer angegebenes Kennwort ein gültiges Benutzerkennwort ist.
Ich nehme an, ich habe einen Benutzer A mit Passwort PA. In dem Skript habe ich Benutzer A gebeten, sein Passwort einzugeben. Wie kann man also überprüfen, ob der eingegebene String wirklich sein Passwort ist?
expect
bei stackoverflow.com/a/1503831/320594 .Antworten:
Da Sie dies in einem Shell-Skript tun möchten, finden Sie unter Wie überprüfe ich das Kennwort unter Linux? Einige Beiträge . (auf Unix.SE , vorgeschlagen von AB ) sind besonders relevant:
/etc/shadow
liefert einen Teil der Lösung.mkpasswd
in Debian (und Ubuntu) vorhandenen Befehls.Um manuell zu überprüfen, ob es sich bei einer Zeichenfolge tatsächlich um ein Benutzerkennwort handelt, müssen Sie es mit demselben Hash-Algorithmus wie im Schatteneintrag des Benutzers und mit demselben Salt wie im Schatteneintrag des Benutzers hashen. Dann kann es mit dem dort gespeicherten Passwort-Hash verglichen werden.
Ich habe ein komplettes, funktionierendes Skript geschrieben, das zeigt, wie das geht.
chkpass
, können Sie es ausführen und es liest eine Zeile von der Standardeingabe und überprüft, ob es das Passwort ist.chkpass user
user
mkpasswd
Dienstprogramm zu erhalten, von dem dieses Skript abhängt.Sicherheitshinweise
Es könnte nicht der richtige Ansatz sein.
Ob ein solcher Ansatz als sicher und ansonsten angemessen angesehen werden sollte oder nicht, hängt von den Details Ihres Anwendungsfalls ab, die Sie (zum Zeitpunkt des Schreibens) nicht angegeben haben.
Es wurde nicht geprüft.
Obwohl ich versucht habe, beim Schreiben dieses Skripts Vorsicht walten zu lassen, wurde es nicht ordnungsgemäß auf Sicherheitslücken überprüft . Es ist als Demonstration gedacht und wäre "Alpha" -Software, wenn es als Teil eines Projekts veröffentlicht würde. Außerdem...
Ein anderer Benutzer, der "zusieht", ist möglicherweise in der Lage, das Salz des Benutzers zu entdecken .
Aufgrund von Einschränkungen beim
mkpasswd
Akzeptieren von Salt-Daten enthält dieses Skript eine bekannte Sicherheitslücke , die Sie je nach Anwendungsfall für akzeptabel halten oder nicht. Standardmäßig können Benutzer auf Ubuntu und den meisten anderen GNU / Linux-Systemen Informationen zu Prozessen anzeigen, die von anderen Benutzern (einschließlich root) ausgeführt werden, einschließlich ihrer Befehlszeilenargumente. Weder die Eingabe des Benutzers noch der gespeicherte Kennwort-Hash werden als Befehlszeilenargument an ein externes Dienstprogramm übergeben. Das aus der Datenbank extrahierte Salt wird jedoch als Befehlszeilenargument für angegeben , da das Dienstprogramm nur so ein Salt als Eingabe akzeptiert.shadow
mkpasswd
Wenn
www-data
erstellen (z. B. ), führt seinen Code aus, oder/proc
)kann die Befehlszeilenargumente so prüfen,
mkpasswd
wie sie von diesem Skript ausgeführt werden, und dann eine Kopie des Salt des Benutzers aus dershadow
Datenbank abrufen. Sie müssen möglicherweise raten können, wann dieser Befehl ausgeführt wird, aber das ist manchmal erreichbar.Ein Angreifer mit Ihrem Salz ist nicht so schlecht wie ein Angreifer mit Ihrem Salz und Hasch , aber es ist nicht ideal. Das Salz liefert nicht genug Informationen, damit jemand Ihr Passwort herausfinden kann. Aber es erlaubt jemandem, Regenbogentabellen oder vorberechnete Wörterbuch-Hashes zu generieren, die für diesen Benutzer auf diesem System spezifisch sind. Dies ist anfangs wertlos. Wenn Ihre Sicherheit jedoch zu einem späteren Zeitpunkt gefährdet wird und der vollständige Hash erhalten wird, kann das Kennwort des Benutzers möglicherweise schneller geknackt werden, bevor er die Möglichkeit hat, es zu ändern.
Daher ist diese Sicherheitslücke ein erschwerender Faktor in einem komplexeren Angriffsszenario und keine vollständig ausnutzbare Sicherheitsanfälligkeit. Und Sie könnten die obige Situation für weit hergeholt halten. Aber ich bin nur ungern jede Methode für die allgemeinen, realen Einsatz zu empfehlen , dass Lecks jegliche nicht-öffentliche Daten aus
/etc/shadow
zu einem Nicht-Root - Benutzer.Sie können dieses Problem vollständig vermeiden, indem Sie:
Seien Sie vorsichtig, wie Sie dieses Skript aufrufen.
Seien Sie vorsichtig, wenn Sie einem nicht vertrauenswürdigen Benutzer erlauben, dieses Skript als Root oder einen Prozess als Root auszuführen, der dieses Skript aufruft . Durch Ändern der Umgebung können sie dieses Skript - oder jedes Skript, das als Root ausgeführt wird - zu beliebigen Aktionen veranlassen . Sofern Sie dies nicht verhindern können, dürfen Sie Benutzern keine erhöhten Berechtigungen für die Ausführung von Shell-Skripten gewähren.
Siehe 10.4. Weitere Informationen zu Shell-Skriptsprachen (sh- und csh-Derivate) finden Sie in David A. Wheelers Secure Programming für Linux und Unix HOWTO . Während sich sein Vortrag auf Setuid-Skripte konzentriert, können andere Mechanismen denselben Problemen zum Opfer fallen, wenn sie die Umgebung nicht ordnungsgemäß bereinigen.
Weitere Hinweise
Es unterstützt nur das Lesen von Hashes aus der
shadow
Datenbank.Passwörter müssen mit einem Shadow versehen sein, damit dieses Skript funktioniert (dh ihre Hashes sollten sich in einer separaten
/etc/shadow
Datei befinden, die nur root lesen kann, nicht in/etc/passwd
).Dies sollte in Ubuntu immer der Fall sein. In jedem Fall kann das Skript , wenn nötig werden , um zu lesen Passwort - Hashes von trivialer Weise erweitert
passwd
sowieshadow
.Halten Sie
IFS
daran , wenn Sie dieses Skript zu ändern.Ich setze
IFS=$
am Anfang, da die drei Daten im Hashfeld eines Schatteneintrags durch getrennt sind$
.$
, weshalb der Hash-Typ und das Salz eher"${ent[1]}"
und"${ent[2]}"
als"${ent[0]}"
und"${ent[1]}"
sind.Die einzigen Stellen in diesem Skript, an denen
$IFS
festgelegt wird, wie die Shell Wörter aufteilt oder kombiniertWenn diese Daten in ein Array aufgeteilt werden, initialisieren Sie sie anhand der nicht zitierten
$(
)
Befehlsersetzung in:Wenn das Array in eine Zeichenfolge rekonstruiert wird, die mit dem vollständigen Feld von verglichen werden soll
shadow
, wird der folgende"${ent[*]}"
Ausdruck verwendet:Wenn Sie das Skript ändern und in anderen Situationen eine Wortteilung (oder Wortverbindung) durchführen lassen, müssen Sie
IFS
für verschiedene Befehle oder verschiedene Teile des Skripts unterschiedliche Werte festlegen.Wenn Sie dies nicht berücksichtigen und davon ausgehen
$IFS
, dass das übliche Leerzeichen ($' \t\n'
) verwendet wird, kann dies dazu führen, dass sich Ihr Skript auf merkwürdige Weise verhält.quelle
Sie können dafür missbrauchen
sudo
.sudo
hat die-l
Option, die sudo-Berechtigungen des Benutzers zu testen und-S
das Kennwort von stdin einzulesen. Unabhängig von der Berechtigungsstufesudo
kehrt der Benutzer bei erfolgreicher Authentifizierung mit dem Beendigungsstatus 0 zurück. Sie können also jeden anderen Beendigungsstatus als Hinweis darauf verwenden, dass die Authentifizierung nicht funktioniert hat (vorausgesetzt, dasssudo
selbst keine Probleme vorliegen, z. B. Berechtigungsfehler oder ungültigesudoers
Konfiguration).Etwas wie:
Dieses Skript hängt stark von der
sudoers
Konfiguration ab. Ich habe das Standard-Setup übernommen. Dinge, die dazu führen können, dass es fehlschlägt:targetpw
oderrunaspw
gesetzt istlistpw
istnever
Andere Probleme sind (danke Eliah):
/var/log/auth.log
sudo
muss als der Benutzer ausgeführt werden, für den Sie sich authentifizieren. Wenn Sie nicht über diesudo
erforderlichen Berechtigungen verfügen , müssen Siesudo -u foo sudo -lS
das Skript als Zielbenutzer ausführen.Der Grund, warum ich hier-docs verwendet habe, ist, das Abhören zu behindern. Eine Variable, die als Teil der Befehlszeile verwendet wird, lässt sich leichter mit
top
oderps
oder anderen Tools zum Überprüfen von Prozessen aufdecken.quelle
sudo
Konfigurationen (wie Sie sagen) und/var/log/auth.log
Aufzeichnungen über jeden Versuch funktioniert , ist dies schnell, einfach und verwendet ein vorhandenes Dienstprogramm, anstatt das Rad neu zu erfinden (sozusagen). Ich schlage vor , EinstellungIFS=
fürread
falsche Erfolge für Leer gepolsterte Benutzereingaben und unwattierter Passwörter zu verhindern, sowie falsche Ausfälle für Leerzeichen gepolsterte Benutzereingabe und gepolsterte Passwörter. (Meine Lösung hatte einen ähnlichen Fehler.) Möglicherweise möchten Sie auch erläutern, wie sie als Benutzer ausgeführt werden muss, dessen Kennwort überprüft wird.sudo -l
bewirkt, dass ein Eintrag mit "COMMAND=list
" geschrieben wird. Übrigens (ohne Bezug), obwohl dies objektiv nicht besser ist, erreicht die Verwendung einer Here-Zeichenfolge anstelle eines Here-Dokuments dasselbe Sicherheitsziel und ist kompakter. Da das Skript bereits die bashisms verwendetread -s
und&>
unter Verwendung vonif sudo -lS &>/dev/null <<<"$PASSWD"; then
nicht weniger tragbar. Ich schlage nicht vor, Sie sollten ändern, was Sie haben (es ist in Ordnung). Ich erwähne es eher, damit die Leser wissen, dass sie diese Option auch haben.sudo -l
etwas deaktiviert ist - vielleicht wurde gemeldet, wenn ein Benutzer versucht, einen Befehl auszuführen, für den er keine Berechtigung hat.Eine andere Methode (wahrscheinlich interessanter für ihre theoretischen Inhalte als für ihre praktischen Anwendungen).
Benutzerpasswörter werden in gespeichert
/etc/shadow
.Die hier gespeicherten Passwörter werden verschlüsselt, wobei in den neuesten Ubuntu-Versionen verwendet wird
SHA-512
.Insbesondere wird bei der Kennworterstellung das Kennwort im Klartext gesalzen und verschlüsselt
SHA-512
.Eine Lösung wäre dann, das gegebene Passwort zu salzen / verschlüsseln und es mit dem verschlüsselten Passwort des Benutzers abzugleichen, das im
/etc/shadow
Eintrag des gegebenen Benutzers gespeichert ist .Um einen schnellen Überblick über die Speicherung der Kennwörter in den einzelnen Benutzereinträgen zu erhalten
/etc/shadow
, finden Sie hier ein Beispiel/etc/shadow
für einen Benutzerfoo
mit Kennwortbar
:foo
: Nutzername6
: Verschlüsselungstyp des PasswortslWS1oJnmDlaXrx1F
: Passworts Verschlüsselungssalzh4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/
:SHA-512
gesalzenes / verschlüsseltes PasswortUm dem angegebenen Passwort
bar
für den angegebenen Benutzerfoo
zu entsprechen, müssen Sie zunächst das Salt abrufen:Dann sollte man das voll gesalzene / verschlüsselte Passwort bekommen:
Dann kann das angegebene Passwort gesalzen / verschlüsselt und mit dem Passwort des gesalzen / verschlüsselten Benutzers abgeglichen werden, das gespeichert ist in
/etc/shadow
:Sie passen! Alles in ein
bash
Skript geschrieben:Ausgabe:
quelle
sudo getent shadow
>>sudo grep ...
. Ansonsten schön. Das ist, woran ich ursprünglich gedacht habe und dann zu faul geworden bin.getent
+grep
+cut
>grep
+cut
getent
kann die Suche für Sie tun. Ich habe mir erlaubt, zu redigieren.mkpasswd
einen Hash aus Benutzereingaben und dem vorhandenen Salt generiert habe (und zusätzliche Funktionen und Diagnosen enthielt), haben Sie stattdessen ein einfaches Python-Programm implementiertmkpasswd
das die wichtigsten Funktionen und diese verwendet. Ich empfehle Ihnen , gesetzt ,IFS=
wenn die Passworteingabe zu lesen, und Zitat${password}
mit"
, so Kennwortversuche mit Leerzeichen nicht das Skript brechen.