Автоматично очищати й захищати історію Bash і Zsh: шифрування, скрипти та таймери

Автоматично очищати й захищати історію Bash і Zsh: шифрування, скрипти та таймери
Категорії: Трюки та лайфхаки

Історія команд у терміналі Linux зручна, але й небезпечна: паролі, токени, адреси серверів — усе це може залишитися в plain text. У цій статті я, Kernelka, покажу, як налаштувати автоочистку та шифрування історії в Bash і Zsh при виході із сесії. Буде безпечно, акуратно й зручно 🔒

Чому варто чистити й шифрувати історію

Навіть якщо ви досвідчено користуєтеся терміналом Linux, випадкове введення секретів безпосередньо в команді — типова помилка. Автоматичне прибирання історії (і/або її шифрування) захищає від:

  • витоку токенів та паролів у ~/.bash_history або ~/.zsh_history;
  • доступу до ваших команд іншими користувачами системи;
  • індексації історії резервними копіями чи збирачами логів.

Нижче — покроково: базова гігієна, шифрування GPG, варіанти без історії та автоматизація задач через cron та systemd timers.

Налаштування Bash: автоочистка й шифрування при виході

Крок 1. Створіть GPG-ключ (один раз)

gpg --full-generate-key
# Подивитися ідентифікатор (email/KEYID)
gpg --list-keys

Запам'ятайте email або KEYID — далі він знадобиться як отримувач для шифрування.

Крок 2. Додайте налаштування до ~/.bashrc

Цей фрагмент зберігає історію в RAM під час сесії та шифрує її при виході у файл із міткою часу. Так ми уникаємо колізій між кількома вікнами термінала.

# ----- Kernelka: безпечна історія для Bash -----
# Редагуйте на свій e-mail або KEYID з gpg --list-keys
export KH_GPG_RECIPIENT="your-email@example.com"

# Гігієна історії
export HISTSIZE=5000
export HISTFILESIZE=5000
export HISTCONTROL=ignoredups:erasedups:ignorespace
shopt -s histappend

# Зберігати історію в RAM (tmpfs) для поточної сесії
_kh_dir="${XDG_RUNTIME_DIR:-/dev/shm}/khist-bash"
mkdir -p "$_kh_dir"
export HISTFILE="$_kh_dir/history-$$.bash"

# Писати команду негайно після виконання
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

# Шифрувати історію при виході із сесії
_kh_encrypt_history_bash() {
  history -a  # дочитати останні команди в файл
  if [[ -s "$HISTFILE" ]]; then
    local ts
    ts=$(date +%F_%H%M%S)
    local tgt="$HOME/.bash_history-${ts}-$$.gpg"
    gpg --yes --encrypt -r "$KH_GPG_RECIPIENT" -o "$tgt" "$HISTFILE" && \
      shred -u -z "$HISTFILE"
  fi
}
trap _kh_encrypt_history_bash EXIT
# ----- /Kernelka -----

Тепер під час кожного виходу з вікна Bash ви отримаєте зашифрований файл у домашній теці, а тимчасовий plaintext у RAM буде надійно стерто.

Налаштування Zsh: автоочистка й шифрування при виході

Крок 1. Увімкніть гігієну історії

# Додайте в ~/.zshrc
setopt APPEND_HISTORY INC_APPEND_HISTORY SHARE_HISTORY \
       HIST_IGNORE_SPACE HIST_REDUCE_BLANKS
HISTSIZE=5000
SAVEHIST=5000

Крок 2. Зберігайте історію в RAM і шифруйте при виході

# ----- Kernelka: безпечна історія для Zsh -----
export KH_GPG_RECIPIENT="your-email@example.com"

_kh_dir="${XDG_RUNTIME_DIR:-/dev/shm}/khist-zsh"
mkdir -p "$_kh_dir"
export HISTFILE="$_kh_dir/history-$$.zsh"

# Записувати команди одразу
precmd() { fc -W }  # зберегти історію перед промптом

# Шифрувати при виході
_kh_encrypt_history_zsh() {
  fc -W  # ще раз переконатися, що останнє записано
  if [[ -s "$HISTFILE" ]]; then
    local ts
    ts=$(date +%F_%H%M%S)
    local tgt="$HOME/.zsh_history-${ts}-$$.gpg"
    gpg --yes --encrypt -r "$KH_GPG_RECIPIENT" -o "$tgt" "$HISTFILE" && \
      shred -u -z "$HISTFILE"
  fi
}
TRAPEXIT() { _kh_encrypt_history_zsh }
# ----- /Kernelka -----

Результат — plaintext-історія живе лише в пам'яті під час сесії, а на диску залишається лише зашифрована копія.

Альтернативні способи

1) Повне вимкнення історії

# Bash
export HISTFILE=/dev/null
export HISTSIZE=0
export HISTFILESIZE=0

# Zsh
unsetopt HIST_SAVE_NO_DUPS
HISTSIZE=0; SAVEHIST=0; export HISTFILE=/dev/null

Різко, але безсумнівно безпечно.

2) Класична автоочистка через файли logout

# ~/.bash_logout
history -c; history -w  # записати порожню історію
shred -u -z ~/.bash_history 2>/dev/null || true

# ~/.zlogout
: >| ~/.zsh_history
shred -u -z ~/.zsh_history 2>/dev/null || true

Майте на увазі: ~/.bash_logout виконується лише для login-shell. У звичайних емуляторах термінала краще використовувати варіант із trap у ~/.bashrc/~/.zshrc.

3) Ротація та прибирання зашифрованих файлів (systemd user)

Це вже приємні трюки Linux і легка автоматизація задач: почистимо зашифровані архіви старше 30 днів.

# ~/.config/systemd/user/khist-prune.service
[Unit]
Description=Prune old encrypted shell histories

[Service]
Type=oneshot
ExecStart=/usr/bin/find %h -maxdepth 1 \( -name ".bash_history-*.gpg" -o -name ".zsh_history-*.gpg" \) -mtime +30 -delete

# ~/.config/systemd/user/khist-prune.timer
[Unit]
Description=Run history prune daily

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=default.target

# Активувати
systemctl --user daemon-reload
systemctl --user enable --now khist-prune.timer

За бажанням замініть на cron, але systemd timers на десктопах працюють стабільніше.

GUI-спосіб: створення GPG-ключа через Seahorse

  1. Встановіть «Passwords and Keys» (Seahorse), якщо його немає.
  2. Відкрийте програму → PGP Keys → плюсик → «PGP Key…» → заповніть ім'я та email.
  3. Створіть ключ і додайте цей email/KEYID у змінну KH_GPG_RECIPIENT у ваших bash скрипти для ~/.bashrc/~/.zshrc.

На KDE можете використати KGpg — кроки схожі ✨

FAQ

Чому моя історія не очищається після закриття вкладки термінала?

Ймовірно, у вас не виконується ~/.bash_logout, бо це не login-shell. Використовуйте варіант із trap EXIT у ~/.bashrc або zsh-функцію TRAPEXIT у ~/.zshrc.

Як виключити секрети з історії, але зберігати решту?

У Bash встановіть HISTCONTROL=ignorespace та вводьте чутливі команди зі стартовим пробілом — такі рядки не потраплять в історію. У Zsh працює setopt HIST_IGNORE_SPACE.

Що робити з кількома одночасними вікнами?

У наведених прикладах історія зберігається в RAM із прив'язкою до PID ($$) — кожне вікно має окремий файл, який шифрується при виході. Це уникає конфліктів запису.

GPG просить пароль під час виходу. Це нормально?

Так. Налаштуйте gpg-agent для кешування пароля або використовуйте розумну тривалість кешу. Не створюйте ключ без пароля — це знижує безпеку.

Як подивитися зашифровану історію?

gpg -d ~/.bash_history-2024-10-01_190200-12345.gpg | less
# або для Zsh
gpg -d ~/.zsh_history-*.gpg | less

Чи підходить це для Fish?

Ідея та інструменти ті самі (RAM + GPG + видалення при виході), але файли/хуки інші. У цій статті зосередженося на Bash і Zsh.

Порада від Kernelka

Тримайте історію корисною, але безпечною: встановіть ліміти HISTSIZE і SAVEHIST, вмикайте ignorespace, а для чутливих сценаріїв використовуйте змінні середовища (наприклад, TOKEN) замість прямого введення секретів. Так ваші трюки Linux залишаться зручними, а ризики — мінімальними 🙂

Підсумок

  • Використайте RAM для тимчасової історії (/dev/shm або $XDG_RUNTIME_DIR).
  • Шифруйте історію GPG при виході з сесії й стирайте plaintext через shred.
  • Налаштуйте гігієну історії: HISTCONTROL/setopt, ліміти розміру, пробіл для чутливих команд.
  • Додайте прибирання архівів через systemd timers для охайності.
  • За потреби — повністю вимкніть історію.

Прокоментувати

На сайті відображається лише твоє ім'я та коментар. Електронна пошта використовується виключно для зв'язку з тобою за потреби.