Dato che vuoi farlo in uno script di shell, un paio di contributi in Come controllare la password con Linux? (su Unix.SE , suggerito da AB ) sono particolarmente rilevanti:
Per controllare manualmente se una stringa è davvero la password di qualche utente, è necessario hash con lo stesso algoritmo di hash come nella voce di ombra per l'utente, con lo stesso sale come in ingresso ombra dell'utente. Quindi può essere confrontato con l'hash della password memorizzato lì.
Ho scritto uno script completo e funzionante che dimostra come farlo.
- Se lo chiami
chkpass
, puoi eseguirlo e leggerà una riga dall'input standard e controllerà se è la password.chkpass user
user
- Installare il pacchetto whois per ottenere l'
mkpasswd
utilità da cui dipende questo script.
- Questo script deve essere eseguito come root per avere successo.
- Prima di utilizzare questo script o parte di esso per svolgere un lavoro reale, vedere le Note sulla sicurezza di seguito.
#!/usr/bin/env bash
xcorrect=0 xwrong=1 enouser=2 enodata=3 esyntax=4 ehash=5 IFS=$
die() {
printf '%s: %s\n' "$0" "$2" >&2
exit $1
}
report() {
if (($1 == xcorrect))
then echo 'Correct password.'
else echo 'Wrong password.'
fi
exit $1
}
(($# == 1)) || die $esyntax "Usage: $(basename "$0") <username>"
case "$(getent passwd "$1" | awk -F: '{print $2}')" in
x) ;;
'') die $enouser "error: user '$1' not found";;
*) die $enodata "error: $1's password appears unshadowed!";;
esac
if [ -t 0 ]; then
IFS= read -rsp "[$(basename "$0")] password for $1: " pass
printf '\n'
else
IFS= read -r pass
fi
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
case "${ent[1]}" in
1) hashtype=md5;; 5) hashtype=sha-256;; 6) hashtype=sha-512;;
'') case "${ent[0]}" in
\*|!) report $xwrong;;
'') die $enodata "error: no shadow entry (are you root?)";;
*) die $enodata 'error: failure parsing shadow entry';;
esac;;
*) die $ehash "error: password hash type is unsupported";;
esac
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
then report $xcorrect
else report $xwrong
fi
Note sulla sicurezza
Potrebbe non essere l'approccio giusto.
Se un approccio come questo debba essere considerato sicuro e altrimenti appropriato dipende dai dettagli sul tuo caso d'uso che non hai fornito (al momento della stesura di questo documento).
Non è stato verificato.
Sebbene abbia provato a prestare attenzione durante la scrittura di questo script, non è stato verificato correttamente per le vulnerabilità di sicurezza . È inteso come una dimostrazione e sarebbe un software "alpha" se rilasciato come parte di un progetto. Inoltre...
Un altro utente che sta "guardando" potrebbe essere in grado di scoprire il sale dell'utente .
A causa delle limitazioni nel modo in cui mkpasswd
accetta i dati salt, questo script contiene un difetto di sicurezza noto , che può essere considerato accettabile a seconda del caso d'uso. Per impostazione predefinita, gli utenti su Ubuntu e la maggior parte degli altri sistemi GNU / Linux possono visualizzare informazioni sui processi eseguiti da altri utenti (incluso root), inclusi i loro argomenti della riga di comando. Né l'input dell'utente né l'hash della password memorizzata vengono passati come argomento della riga di comando a nessuna utility esterna. Ma il salt , estratto dal shadow
database, viene fornito come argomento della riga di comando mkpasswd
, poiché questo è l'unico modo in cui l'utilità accetta un salt come input.
Se
- un altro utente sul sistema, o
- chiunque abbia la possibilità di creare un account utente (ad es.
www-data
) eseguire il proprio codice o
- chiunque altrimenti possa visualizzare informazioni sui processi in esecuzione (anche ispezionando manualmente le voci in
/proc
)
è in grado di controllare gli argomenti della riga di comando mkpasswd
mentre viene eseguito da questo script, quindi possono ottenere una copia del sale dell'utente dal shadow
database. Essi potrebbero devono essere in grado di indovinare quando quel comando viene eseguito, ma che a volte è realizzabile.
Un attaccante con il tuo sale non è cattivo come un attaccante con il tuo sale e hash , ma non è l'ideale. Il salt non fornisce abbastanza informazioni per qualcuno per scoprire la tua password. Ma consente a qualcuno di generare tabelle arcobaleno o hash di dizionari pre-calcolati specifici per quell'utente su quel sistema. Inizialmente non ha valore, ma se la tua sicurezza viene compromessa in un secondo momento e viene ottenuto l'intero hash, potrebbe essere crackato più rapidamente per ottenere la password dell'utente prima che abbia la possibilità di cambiarla.
Pertanto, questo difetto di sicurezza è un fattore esacerbante in uno scenario di attacco più complesso piuttosto che una vulnerabilità completamente sfruttabile. E potresti considerare la situazione di cui sopra inverosimile. Ma sono riluttante a raccomandare qualsiasi metodo per un uso generale e reale che diffonda qualsiasi dato non pubblico da /etc/shadow
un utente non root.
È possibile evitare completamente questo problema:
- scrivere parte del tuo script in Perl o in qualche altra lingua che ti consenta di chiamare le funzioni C, come mostrato nella risposta di Gilles alla relativa domanda Unix.SE , oppure
- scrivere l'intero script / programma in una tale lingua, piuttosto che usare bash. (In base al modo in cui hai taggato la domanda, sembra che tu preferisca usare bash.)
Fai attenzione a come chiami questo script.
Se si consente a un utente non attendibile di eseguire questo script come root o di eseguire qualsiasi processo come root che chiama questo script, fare attenzione . Modificando l'ambiente, possono fare in modo che questo script, o qualsiasi script eseguito come root, faccia qualsiasi cosa . A meno che non sia possibile evitare che ciò accada, non è necessario consentire agli utenti privilegi elevati per l'esecuzione di script di shell.
Vedi 10.4. Shell Scripting Languages (sh and csh Derivatives) in Programmazione sicura di David A. Wheeler per Linux e Unix HOWTO per ulteriori informazioni al riguardo. Mentre la sua presentazione si concentra su script setuid, altri meccanismi possono cadere in preda ad alcuni degli stessi problemi se non disinfettano correttamente l'ambiente.
Altre note
Supporta la lettura di hash solo dal shadow
database.
Le password devono essere ombreggiate affinché questo script funzioni (vale a dire, i loro hash dovrebbero essere in un /etc/shadow
file separato che solo root può leggere, non in /etc/passwd
).
Questo dovrebbe essere sempre il caso di Ubuntu. In ogni caso, se necessario, lo script può essere banalmente esteso per leggere gli hash delle password da passwd
così come shadow
.
Tenere IFS
presente quando si modifica questo script.
Ho impostato IFS=$
all'inizio, poiché i tre dati nel campo hash di una voce shadow sono separati da $
.
- Hanno anche un vantaggio
$
, motivo per cui il tipo di hash e il sale sono "${ent[1]}"
e "${ent[2]}"
piuttosto che "${ent[0]}"
e "${ent[1]}"
, rispettivamente.
Le uniche posizioni in questo script in cui si $IFS
determina come la shell divide o combina le parole
quando questi dati vengono suddivisi in un array, inizializzandoli dalla $(
)
sostituzione di comando non quotata in:
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
quando l'array viene ricostituito in una stringa da confrontare con l'intero campo da shadow
, l' "${ent[*]}"
espressione in:
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
Se modifichi lo script e esegui la suddivisione delle parole (o l'unione delle parole) in altre situazioni, dovrai impostare IFS
valori diversi per comandi diversi o parti diverse dello script.
Se non lo tieni a mente e presumi che $IFS
sia impostato sul solito spazio bianco ( $' \t\n'
), potresti finire per far comportare il tuo script in modi piuttosto strani.