Поскольку вы хотите сделать это в сценарии оболочки, пара вкладов в Как проверить пароль в Linux? (на Unix.SE , предложенный AB ) особенно актуальны:
Чтобы вручную проверить, является ли строка действительно паролем какого-либо пользователя, вы должны хешировать его с помощью того же алгоритма хеширования, что и в теневой записи пользователя, с той же солью, что и в теневой записи пользователя. Затем его можно сравнить с хешем пароля, хранящимся там.
Я написал полный рабочий скрипт, демонстрирующий, как это сделать.
- Если вы назовете его
chkpass
, вы можете запустить, и он будет читать строку из стандартного ввода и проверять, если это пароль.chkpass user
user
- Установите пакет whois , чтобы получить
mkpasswd
утилиту, от которой зависит этот скрипт.
- Этот сценарий должен быть запущен от имени пользователя root для успеха.
- Прежде чем использовать этот сценарий или любую его часть для реальной работы, ознакомьтесь с примечаниями по безопасности ниже.
#!/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
Примечания по безопасности
Это может быть не правильный подход.
Вопрос о том, следует ли считать такой подход безопасным и иным ли уместным, зависит от деталей вашего варианта использования, которые вы не предоставили (на момент написания статьи).
Это не было проверено.
Хотя я пытался проявлять осторожность при написании этого сценария, он не был должным образом проверен на наличие уязвимостей в безопасности . Он предназначен для демонстрации и будет "альфа" программным обеспечением, если будет выпущен как часть проекта. Более того...
Другой пользователь, который «смотрит», может обнаружить соль пользователя .
Из-за ограничений в том, как mkpasswd
принимать соленые данные, этот сценарий содержит известный недостаток безопасности , который вы можете или не можете считать приемлемым в зависимости от варианта использования. По умолчанию пользователи в Ubuntu и большинстве других систем GNU / Linux могут просматривать информацию о процессах, выполняемых другими пользователями (включая root), включая их аргументы командной строки. Ни ввод пользователя, ни сохраненный хэш пароля не передаются в качестве аргумента командной строки какой-либо внешней утилите. Но соль , извлеченная из shadow
базы данных, будет дана в качестве аргумента командной строки для mkpasswd
, так как это единственный способ , которым утилита принимает соль в качестве входных данных.
Если
- другой пользователь в системе, или
- любой, кто имеет возможность сделать любую учетную запись пользователя (например,
www-data
) запустить свой код, или
- любой, кто в противном случае может просматривать информацию о запущенных процессах (в том числе путем ручной проверки записей в
/proc
)
может проверить аргументы командной строки, mkpasswd
поскольку он запускается этим сценарием, затем они могут получить копию соли пользователя из shadow
базы данных. Они , возможно , должны быть в состоянии угадать , когда эта команда выполняется, но иногда достижимо.
Атакующий с вашей солью не так плох, как атакующий с вашей солью и хэшем , но это не идеально. Соль не дает достаточно информации, чтобы кто-то мог найти ваш пароль. Но это позволяет кому-то генерировать радужные таблицы или предварительно вычисленные хеши словаря, специфичные для этого пользователя в этой системе. Это изначально бесполезно, но если ваша безопасность будет скомпрометирована на более позднем этапе и будет получен полный хэш, его можно будет взломать быстрее, чтобы получить пароль пользователя, прежде чем он получит возможность изменить его.
Таким образом, этот недостаток безопасности является обостряющим фактором в более сложном сценарии атаки, а не полностью уязвимой уязвимостью. И вы могли бы рассмотреть вышеуказанную ситуацию надуманным. Но я не хочу рекомендовать любой метод для общего, реального использования, который пропускает любые непубличные данные от /etc/shadow
пользователя без полномочий root.
Вы можете полностью избежать этой проблемы:
- написание части вашего сценария в Perl или другом языке , который позволяет вызывать функции C, как и показаны в ответе Жиля в к соответствующему Unix.SE вопросу , или
- написание всего сценария / программы на таком языке, а не использование bash. (Судя по тому, как вы пометили вопрос, похоже, вы предпочитаете использовать bash.)
Будьте осторожны, как вы называете этот сценарий.
Если вы позволяете ненадежному пользователю запускать этот сценарий от имени пользователя root или запускать любой процесс от имени пользователя root, который вызывает этот сценарий, будьте осторожны . Изменяя среду, они могут заставить этот скрипт - или любой скрипт, который запускается от имени root - делать что угодно . Если вы не можете предотвратить это, вы не должны разрешать пользователям повышенные привилегии для запуска сценариев оболочки.
Смотрите 10.4. Языки сценариев оболочки (производные sh и csh) в книге Дэвида А. Уилера по безопасному программированию для Linux и Unix HOWTO для получения дополнительной информации об этом. Хотя его презентация сосредоточена на сценариях setuid, другие механизмы могут стать жертвами некоторых из тех же проблем, если они неправильно очищают среду.
Другие заметки
Он поддерживает чтение хэшей только из shadow
базы данных.
Для работы этого скрипта пароли должны быть затенены (т. Е. Их хеши должны находиться в отдельном /etc/shadow
файле, который может прочитать только пользователь root, а не в нем /etc/passwd
).
Это всегда должно быть в Ubuntu. В любом случае, если необходимо, скрипт может быть тривиально расширен для чтения хешей паролей, passwd
а также shadow
.
Имейте IFS
в виду, когда модифицируете этот скрипт.
Я установил IFS=$
в начале, так как три данных в хэш-поле теневой записи разделены $
.
- Они также имеют ведущие
$
, поэтому хэш-тип и соль есть "${ent[1]}"
и, "${ent[2]}"
а не "${ent[0]}"
и "${ent[1]}"
, соответственно.
Единственные места в этом скрипте, где $IFS
определяется, как оболочка разделяет или объединяет слова,
когда эти данные разбиваются на массив, инициализируя его из $(
)
подстановки команды без кавычек в:
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
когда массив восстанавливается в строку для сравнения с полным полем из shadow
, "${ent[*]}"
выражение в:
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
Если вы модифицируете скрипт и выполняете его деление слов (или объединение слов) в других ситуациях, вам нужно будет установить IFS
разные значения для разных команд или разных частей скрипта.
Если вы не помните об этом и предполагаете, $IFS
что установлен обычный пробел ( $' \t\n'
), вы можете в конечном итоге заставить свой скрипт вести себя довольно странным образом.