Karena Anda ingin melakukan ini dalam skrip shell, beberapa kontribusi dalam Cara memeriksa kata sandi dengan Linux? (pada Unix.SE , disarankan oleh AB ) sangat relevan:
Untuk secara manual memeriksa apakah suatu string benar-benar beberapa kata sandi pengguna, Anda harus mengirisnya dengan algoritma hash yang sama seperti pada entri bayangan pengguna, dengan garam yang sama seperti pada entri bayangan pengguna. Kemudian bisa dibandingkan dengan kata sandi hash yang tersimpan di sana.
Saya telah menulis naskah yang lengkap dan berfungsi yang menunjukkan bagaimana melakukan ini.
- Jika Anda menamainya
chkpass
, Anda dapat menjalankan dan itu akan membaca baris dari input standar dan memeriksa apakah itu kata sandi.chkpass user
user
- Pasang whois paket untuk mendapatkan
mkpasswd
utilitas yang menjadi dasar skrip ini.
- Script ini harus dijalankan sebagai root untuk berhasil.
- Sebelum menggunakan skrip ini atau bagian mana pun untuk melakukan pekerjaan nyata, silakan lihat Catatan Keamanan di bawah ini.
#!/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
Catatan Keamanan
Mungkin itu bukan pendekatan yang tepat.
Apakah pendekatan seperti ini harus dianggap aman atau tidak, tergantung pada detail tentang kasus penggunaan yang belum Anda berikan (pada tulisan ini).
Belum diaudit.
Meskipun saya sudah berusaha berhati-hati saat menulis skrip ini, itu belum diaudit dengan baik untuk kerentanan keamanan . Ini dimaksudkan sebagai demonstrasi, dan akan menjadi perangkat lunak "alpha" jika dirilis sebagai bagian dari proyek. Selanjutnya...
Pengguna lain yang "menonton" mungkin dapat menemukan pengguna tersebut garam .
Karena keterbatasan dalam cara mkpasswd
menerima data garam, skrip ini berisi kelemahan keamanan yang diketahui , yang Anda mungkin atau mungkin tidak anggap dapat diterima tergantung pada kasus penggunaan. Secara default, pengguna di Ubuntu dan sebagian besar sistem GNU / Linux lainnya dapat melihat informasi tentang proses yang dijalankan oleh pengguna lain (termasuk root), termasuk argumen baris perintah mereka. Baik input pengguna maupun hash kata sandi yang disimpan dilewatkan sebagai argumen baris perintah ke utilitas eksternal apa pun. Tapi garam , diambil dari shadow
basis data, yang diberikan sebagai argumen baris perintah untuk mkpasswd
, karena ini adalah satu-satunya cara yang utilitas menerima garam sebagai masukan.
Jika
- pengguna lain pada sistem, atau
- siapa pun yang memiliki kemampuan untuk membuat akun pengguna apa pun (misalnya,
www-data
) menjalankan kode mereka, atau
- siapa pun yang dapat melihat informasi tentang proses yang sedang berjalan (termasuk dengan memeriksa entri secara manual
/proc
)
dapat memeriksa argumen baris perintah mkpasswd
saat dijalankan oleh skrip ini, kemudian mereka dapat memperoleh salinan garam pengguna dari shadow
database. Mereka mungkin harus bisa menebak kapan perintah itu dijalankan, tetapi itu kadang-kadang dapat dicapai.
Seorang penyerang dengan garam Anda tidak seburuk penyerang dengan garam dan hash Anda , tetapi itu tidak ideal. Garam tidak memberikan informasi yang cukup bagi seseorang untuk menemukan kata sandi Anda. Tapi itu memungkinkan seseorang untuk menghasilkan tabel pelangi atau hash kamus pra-dihitung khusus untuk pengguna pada sistem itu. Ini pada awalnya tidak berharga, tetapi jika keamanan Anda dikompromikan di kemudian hari dan hash lengkap diperoleh, maka dapat dipecah lebih cepat untuk mendapatkan kata sandi pengguna sebelum mereka mendapatkan kesempatan untuk mengubahnya.
Dengan demikian kelemahan keamanan ini merupakan faktor yang memperburuk skenario serangan yang lebih kompleks daripada kerentanan sepenuhnya dapat dieksploitasi. Dan Anda mungkin menganggap situasi di atas tidak masuk akal. Tapi saya enggan untuk merekomendasikan metode apapun untuk umum, penggunaan dunia nyata bahwa kebocoran setiap data non-publik dari /etc/shadow
ke pengguna non-root.
Anda dapat menghindari masalah ini sepenuhnya dengan:
- menulis bagian dari naskah Anda di Perl atau bahasa lain yang memungkinkan Anda menelepon fungsi C, seperti yang ditunjukkan dalam jawaban Gilles untuk pertanyaan Unix.SE terkait , atau
- menulis seluruh skrip / program Anda dalam bahasa seperti itu, daripada menggunakan bash. (Berdasarkan cara Anda menandai pertanyaan, tampaknya Anda lebih suka menggunakan bash.)
Berhati-hatilah dengan panggilan skrip ini.
Jika Anda mengizinkan pengguna yang tidak dipercaya untuk menjalankan skrip ini sebagai root atau menjalankan proses apa pun sebagai root yang memanggil skrip ini, berhati-hatilah . Dengan mengubah lingkungan, mereka dapat membuat skrip ini - atau skrip apa pun yang berjalan sebagai root - melakukan apa saja . Kecuali Anda dapat mencegah hal ini terjadi, Anda tidak boleh mengizinkan pengguna hak istimewa tinggi untuk menjalankan skrip shell.
Lihat 10.4. Bahasa Shell Scripting (turunan sh dan csh) di Pemrograman Aman David A. Wheeler untuk Linux dan Unix HOWTO untuk informasi lebih lanjut tentang ini. Sementara presentasinya berfokus pada skrip setuid, mekanisme lain dapat menjadi mangsa beberapa masalah yang sama jika mereka tidak membersihkan lingkungan dengan benar.
Catatan lain
Ini mendukung bacaan hash dari shadow
database saja.
Kata sandi harus dibayangi agar skrip ini berfungsi (yaitu, hash mereka harus dalam /etc/shadow
file terpisah yang hanya dapat dibaca oleh root, bukan di /etc/passwd
).
Ini harus selalu menjadi kasus di Ubuntu. Dalam kasus apa pun, jika diperlukan, skrip dapat dengan mudah diperluas untuk membaca hash kata sandi passwd
juga shadow
.
Perlu IFS
diingat saat memodifikasi skrip ini.
Saya atur IFS=$
di awal, karena tiga data dalam bidang hash dari entri bayangan dipisahkan oleh $
.
- Mereka juga memiliki terkemuka
$
, itulah sebabnya jenis dan garam hash "${ent[1]}"
dan "${ent[2]}"
bukannya "${ent[0]}"
dan "${ent[1]}"
, masing-masing.
Satu-satunya tempat di skrip ini yang $IFS
menentukan bagaimana shell membagi atau menggabungkan kata-kata
ketika data ini dipecah menjadi sebuah array, dengan menginisialisasi dari $(
)
substitusi perintah yang tidak dikutip dalam:
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
ketika array disusun kembali menjadi string untuk dibandingkan dengan bidang penuh dari shadow
, "${ent[*]}"
ekspresi di:
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
Jika Anda memodifikasi skrip dan membuatnya melakukan pemisahan kata (atau penggabungan kata) dalam situasi lain, Anda harus mengatur IFS
nilai yang berbeda untuk perintah yang berbeda atau bagian skrip yang berbeda.
Jika Anda tidak mengingatnya dan menganggap $IFS
diatur ke spasi putih biasa ( $' \t\n'
), Anda bisa membuat skrip Anda berperilaku dalam beberapa cara yang tampak aneh.