DIY Хранение Паролей

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Последнее время пребываю в легком шоке от происходящего. И крупные компании, и 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/


Интересные статьи

Интересные статьи

Иногда необходимо изменить размер изображения с сохранением пропорции сторон. Особенно, когда это очень большое количество файлов. Это приложение позволяет изменить размер изображения, сохранить его в...
В этой статье мы рассмотрим, как система управления 1С-Битрикс справляется с большими нагрузками. Данный вопрос особенно актуален сегодня, когда электронная торговля начинает конкурировать по обороту ...
Ваш сайт работает на 1С-Битрикс? Каждому клиенту вы даёте собственную скидку или назначаете персональную цену на товар? Со временем в вашей 1С сложилась непростая логика ценообразования и формирования...
Если честно, к Д7 у меня несколько неоднозначное отношение. В некоторых местах я попискиваю от восторга, а в некоторых хочется топать ногами и ругаться неприличными словами.
Привет Хабр! Каждый из нас хранит какую-нибудь информацию, некоторые для этого используют секретики и лайфхаки. Лично я люблю понажимать кнопку фоторужья и сегодня хотел бы поделиться своим опыто...