https://habr.com/ru/company/macloud/blog/566748/- Блог компании Маклауд
- Настройка Linux
- Python
Как вывести свою систему на новый уровень безопасности с модулями python-gnupg и getpass4.
Изображение : freeGraphicToday, via Pixabay. CC0.
В условиях растущих требований к безопасности создание и хранение паролей может вызвать вопросы не только для пользователей, но и у разработчиков и системных администраторов. Специалисты и другие осведомлённые люди знают, что пароли нужно хранить в зашифрованном виде. Уже на этапе ввода символы пароля нужно скрывать от любых глаз (даже от того человека, который его вводит). Всегда ли мы можем выполнить хотя бы эти требования?
Я единственный пользователь своего ноутбука, а на его борту крутится ОС семейства Linux. Поэтому меня не беспокоят пользователи, которые могут случайно или неслучайно посмотреть мои конфигурационные файлы, работая на этом же компьютере. Я решил заморочиться и повысить безопасность своего личного ноутбука, и на то есть свои причины. Да, я шифрую свой домашний каталог, но как только вхожу в систему, любой пароль, хранящийся в виде простого текста в файле конфигурации, потенциально может быть уязвим для чересчур любопытных глаз.
К тому же, я использую почтовый клиент
Mutt. Он позволяет мне читать и составлять электронные письма прямо в Linux-терминале. Мне удобно, мне нравится. Правда, ему нужно, чтобы я хранил пароль в файле конфигурации (.mutt), либо всё время вводил пароль в интерактивном режиме. Поэтому я ограничил права доступа к моему конфигурационному файлу Mutt, чтобы его мог видеть только я.
Но есть ещё один важный момент: я периодически пишу технические статьи, составляю туториалы, помогаю людям в сообществе и публикую много своего кода в общедоступных репозиториях, публикую скриншоты своего экрана, часто показываю что-то на примере своей рабочей системы. Если по недосмотру меня угораздит засветить в Интернете (или где-то ещё) данные (и в том числе пароли) из моих конфигурационных файлов, это бросит неприятную тень на мою репутацию и безопасность. Так что надо подстраховаться.
Ну и, если вдруг злоумышленник завладеет моим ноутбуком или каким-то другим образом получит доступ в систему, он не сможет получить мой пароль без боя, просто запустив
cat для просмотра логов и конфигов.
Поиск решения задачи
Я решил, что лучший способ защитить мой пароль в Mutt — ввести пароль с клавиатуры, сохранить его в зашифрованном файле GPG, написать на Python скрипт расшифровки для моего GPG-пароля, ну и заодно обеспечить передачу пароля Mutt в скрипт
offlineimap, который я использую для локальной синхронизации моего ноутбука с почтовым сервером.
Из подзаголовка статьи ясно, что я буду использовать модули
python-gnupg и getpass. Модуль Python
python-gnupg — это обёртка для инструмента шифрования gpg. Учтите, python-gnupg не следует путать с модулем под названием
gnupg. GnuPG (
GPG) — это утилита шифрования для Linux, и я использую её с 2009 года или около того. С ней я чувствую себя комфортно и верю в её безопасность.
Получить пользовательский ввод с помощью Python довольно просто. Вы вызываете
input, и всё, что введёт пользователь сохраняется в переменной:
print("Enter password: ")
myinput = input()
print("You entered: ", myinput)
И в этом случае есть одна громадная проблема: когда я ввожу пароль в терминале, всё, что я набираю, видно всем, кто смотрит через моё плечо или просматривает историю моего терминала:
$ ./test.py
Enter password: my-Complex-Passphrase
Написание скрипта с python-gnupg и getpass
Как это часто бывает, ничего самому писать не надо, потому что уже существует модуль Python, который позволяет решить проблему. Это модуль
getpass4. С точки зрения пользователя он ведёт себя точно так же, как любое стандартное приглашение к вводу, за исключением того, что не отображает введённые символы.
Установим оба модуля с помощью
pip:
$ python -m pip install --user \
python-gnupg getpass4
У меня получился вот такой скрипт для создания пароля с невидимым вводом и расшифровкой:
#!/usr/bin/env python
# by Seth Kenlon
# GPLv3
# install deps:
# python3 -m pip install --user python-gnupg getpass4
import gnupg
import getpass
from pathlib import Path
def get_api_pass():
homedir = str(Path.home())
gpg = gnupg.GPG(gnupghome=os.path.join(homedir,".gnupg"), use_agent=True)
passwd = getpass.getpass(prompt="Enter your GnuPG password: ", stream=None)
with open(os.path.join(homedir,'.mutt','pass.gpg'), 'rb') as f:
apipass = (gpg.decrypt_file(f, passphrase=passwd))
f.close()
return str(apipass)
if __name__ == "__main__":
apipass = get_api_pass()
print(apipass)
Сохраните файл как password_prompt.py, если хотите попробовать скрипт у себя. Если вместе с ним вы хотите использовать offlineimap, укажите в конфигурационном файле
.offlineimaprc имя и путь к скрипту с паролем (у меня это
~/.mutt/password_prompt.py). Правда, там нужно сделать ещё кое-что, но об этом позже.
Тестирование скрипта с gpg
Надеюсь, у вас уже установлен gpg, так как сейчас мы будем создавать зашифрованный файл пароля и тестировать скрипт.
Шифруем:
$ echo "hello world" > pass
$ gpg --encrypt pass
$ mv pass.gpg ~/.mutt/pass.gpg
$ rm pass
Запускаем созданный ранее скрипт:
$ python ~/.mutt/password_prompt.py
Enter your GPG password:
hello world
Ура! При вводе ничего не отображается, но если вы правильно введёте пароль (нужно ввести
hello world), на следующей строке вы увидите тестовое сообщение «hello world». Оно же и является паролем, полученным в результате расшифровки файла
~/.mutt/pass.gpg. Значит, скрипт работает правильно.
Интеграция с offlineimap
Я выбрал Python, потому что знал, что offlineimap может вызывать скрипты, написанные на Python. Если вы уже пользуетесь offlineimap, вы поймете, что единственная необходимая «интеграция» сводится к изменению двух строк в вашем файле .offlineimaprc (точнее — к добавлению одной строки и изменению другой).
Сначала добавьте строку, ссылающуюся на файл нашего скрипта:
pythonfile = ~/.mutt/password_prompt.py
Теперь вместо пароля в строке с remotepasseval после знака «=» вызовите функцию get_api_pass(), которая живёт в скрипте password_prompt.py:
remotepasseval = get_api_pass()
Всё! Теперь никто не сможет прочитать пароль из вашего конфигурационного файла!
Безопасность даёт свободу
Иногда кажется, что у меня паранойя: я много думаю о тонкостях обеспечения безопасности на моём личном компьютере. Действительно ли SSH конфиг должен иметь разрешения
chmod 600? Действительно ли имеет значение, что пароль электронной почты находится в конфигурационном файле, спрятанном в скрытой папке, которая называется, как ни странно,
.mutt? Хотя написать подобный скрипт на Python можно и для других конфигурационных файлов.
Зная, что в моих файлах конфигурации отсутствуют незашифрованные конфиденциальные данные, мне намного проще публиковать файлы в общедоступных репозиториях Git, копировать и вставлять сниппеты на форумах и делиться своими знаниями в форме актуальных, рабочих файлов конфигурации. С этой точки зрения, повышение уровня безопасности облегчило мне жизнь. А с таким количеством Python-модулей на все случаи жизни, сделать это было достаточно легко.
Аренда облачного сервера с быстрыми NVMе-дисками и посуточной оплатой у хостинга Маклауд.