Последнее время пребываю в легком шоке от происходящего. И крупные компании, и Open Source сообщество показали чего стоят либеральные ценности. Риторика и пропаганда с обеих сторон просто поражает своим цинизмом и “человеколюбием”…
Все свои данные срочным порядком перенёс из внешних по отношении к РФ сервисов, сделал локальные бэкапы. Если перенос файлов, документов, почты, репозиториев сложностей не вызывает, то с паролями не так всё просто. Менеджеры паролей удобны, но уровень доверия к сторонним решениям всегда был невысок. При этом “набросать” своё решение вполне реально. Можно считать эту статью краткой инструкцией, поэтому: меньше слов, больше кода.
Crypto API есть и на фронте и на бэке, его подкрепляет множество стандартов. Однако, быстрее всего решить эту задачу через Bash. Должно получиться примерно 100 строк вместе с хэлпом. Суть решения от этого не поменяются, а, в моём случае, на этом можно и остановиться.
Как хранить секреты
Выбираем алгоритм шифрования на свой вкус. В данном случае вполне подойдёт AES-256 в режиме CBC. Про режимы шифрования есть статья на wiki. Соль в данном случае не ясно для чего может пригодиться. Получаем следующую команду для шифрования секретов:
$ echo -n "<секрет>" | openssl aes-256-cbc -nosalt -pbkdf2 -base64
Опция -n в данном случае позволяет избавиться от символа перевода строки в конце, в противном случае, перевод строки тоже будет закодирован openssl.
PBKDF2 — стандарт формирования ключа на основе пароля — необходимо указать во избежание назойливого warning.
В момент вызова openssl попросит ввести пароль, который в данном случае является мастер-паролем. На выходе получим зашифрованный секрет в формате Base64, который можно “положить” в любое удобное место. Например, в пользовательскую директорию:
$ echo -n "<секрет>" | openssl aes-256-cbc -nosalt -pbkdf2 -base64 \ > ~/.imn/"<имя секрета>".pub
Копию я закинул на Яндекс.Диск …
Соответственно, чтобы восстановить зашифрованный секрет достаточно произвести обратную операцию:
$ openssl aes-256-cbc -nosalt -pbkdf2 -base64 -d < ~/.imn/"<имя секрета>".pub
Опция -d указывает на дешифрование, остальные опции openssl неизменны по понятным причинам. При вызове потребуется ввести мастер-пароль.
Вот так просто и без затей… Осталось несколько нюансов.
Как генерировать секреты
Брать секреты “из головы” не только неудобно (при наличии мастер-пароля), но и небезопасно. Наша утилита должна уметь генерировать криптостойкие секреты, по аналогии с многочисленными собратьями.
И снова openssl помогает решить проблему:
$ openssl rand -base64 "<длина секрета>"
Кратная трём длина секрета позволит избежать знаков равенства в конце генерируемой строки, которые служат в кодировке Base64 для “набивки”.
Удобно совместить операции генерации, шифрования и сохранения секрета:
$ local secret=$(openssl rand -base64 "<длина секрета>") $ echo -n "$secret" | openssl aes-256-cbc -nosalt -pbkdf2 -base64 \ > ~/.imn/"<имя секрета>".pub
Копирование “свежего” секрета в буфер обмена варьируется от операционной системы. В Linux — это, скорее всего, xlip:
$ echo "$secret" | xclip
В WSL под Windows — это clip.exe:
$ echo "$secret" | clip.exe
Как импортировать секреты из Chrome
Хранить секреты в менеджере паролей Chrome конечно удобно, но… с учетом новых обстоятельств, лучше не стоит.
Перенос секретов из Chrome, ровно как и из других менеджеров паролей — задача тривиальная. Экспортируем секреты в формате CSV. Получится нечто следующее:
# name,url,usename,password ,<https://foo.com/bar,ivanov,qwerty> ,<https://plugh.com/quux,petrov,asdfg>
Первая строка в CSV формате — это перечисление имён колонок. Отбрасываем строку с метаинформацией (парсим начиная со второй +2):
$ cat chrome-secrets.csv | tail -n+2
И парсим при помощи read строка за строкой:
cat chrome-secrets.csv | tail -n+2 | \ while IFS=',' read -r name url username secret; do echo Имя секрета: "$url@$username" echo Секрет: "$secret" done
В качестве уникального имени секрета лучше использовать сочетание URL и логин.
Полный листинг
Чтобы зря не тратить ваше время приведу то, что получилось у меня:
#!/usr/bin/env bash DIR=~/.imn ALGO=(aes-256-cbc -nosalt -pbkdf2 -base64) mkdir -p "$DIR" store() { local name="$1" shift local secret secret=$(rand_secret "$@") store_secret "$name" "$secret" } rand_secret() { if [[ $# -gt 0 ]]; then openssl rand "$@" else openssl rand -base64 30 fi } store_secret() { local name="$1" local secret="$2" shift 2 echo -n "$secret" | openssl "${ALGO[@]}" "$@" > "$DIR"/"$name".pub print_secret "$secret" } restore() { assert_pub_key "$1" local name="$1" local secret secret=$(openssl "${ALGO[@]}" -d < "$DIR"/"$name".pub) print_secret "$secret" } assert_pub_key() { local name="$1" if [[ ! -f "$DIR"/"$name".pub ]]; then echo Public key "\"$name\"" not found >&2 exit 1 fi } print_secret() { printf '%s\n' "$1" } import_chrome_csv() { # name,url,usename,password cut -f2-4 -d',' | import_csv "$@" } import_csv() { grep -v password | while IFS=',' read -r url username secret; do local origin="${url#*://}" origin="${origin%%/*}" local name="$origin@$username" echo "$name" store_secret "$name" "$secret" "$@" >/dev/null done } case "$1" in --help|-h) echo "Generate and store random secret:" echo " imn.sh store|s <name>" echo "Restore secret:" echo " imn.sh [restore|r] <name>" echo "Import secrets from Chrome's CSV:" echo " imn.sh chrome <path to CSV> -k <master password>" ;; chrome) shift csv=$1 shift import_chrome_csv "$@" < "$csv" ;; store|s|gen|g) shift store "$@" ;; restore|r) shift restore "$@" ;; *) restore "$@" ;; esac
Если Вы такой же параноик (в хорошем смысле) как и я, милости прошу в комментарии, всегда рад пообщаться с единомышленниками.
ссылка на оригинал статьи https://habr.com/ru/post/656915/
Добавить комментарий