0Pricing
Linux Command Line & Bash Scripting Mastery · Lekcja

Bezpieczne obchodzenie się z sekretami i higiena środowiska

Nie umieszczaj poświadczeń na listach procesów ani w logach, korzystając ze standardowego wejścia, plików i oczyszczonego środowiska.

Bezpieczne obchodzenie się z sekretami i higiena środowiska to bezpłatna lekcja Linux Command Line & Bash Scripting Mastery na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Linux Command Line & Bash Scripting Mastery, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Dlaczego higiena sekretów ma znaczenie

Sekrety — klucze API, hasła i tokeny — to najbardziej wrażliwe dane w każdym systemie. Niewłaściwe obchodzenie się z nimi w skryptach Basha jest jednym z najczęstszych i najbardziej szkodliwych błędów bezpieczeństwa.

  • Listy procesów: argumenty przekazywane do poleceń pojawiają się w ps aux, /proc/<pid>/cmdline i systemowych dziennikach audytowych — są widoczne dla wszystkich użytkowników hosta.
  • Historia powłoki: polecenia wpisywane interaktywnie (a czasem także skrypty) są zapisywane w ~/.bash_history.
  • Pliki logów: ślady set -x, logi aplikacji i dane wyjściowe CI/CD mogą zawierać wartości zmiennych.
  • Wyciek przez środowisko: procesy potomne dziedziczą całe środowisko procesu nadrzędnego, w tym wyeksportowane sekrety.

Wzmocniony skrypt traktuje sekrety jak materiały radioaktywne — minimalizuje czas ich ekspozycji, ogranicza powierzchnię narażenia i oczyszcza wszystko przed przekazaniem dalej.

Powierzchnia ataku związana z listą procesów

Gdy sekret jest przekazywany jako argument wiersza poleceń, każdy użytkownik systemu może natychmiast odczytać go za pomocą ps. Nie jest to zagrożenie czysto teoretyczne — regularnie wykorzystuje się je w środowiskach współdzielonego hostingu i kontenerach.

Poniższy fragment pokazuje problem i jego rozwiązanie obok siebie.

#!/usr/bin/env bash
# DANGEROUS: password visible in 'ps aux' output
# curl -u "admin:SuperSecret123" https://api.example.com/data

# SAFE: pass credentials via stdin or a flag that reads from a file
# Many tools support reading secrets from stdin with '-' or dedicated flags:

# Option 1 — pipe the secret so it never appears in argv
echo 'SuperSecret123' | curl -u 'admin' --password-stdin \
  https://api.example.com/data 2>/dev/null || true

# Option 2 — write a temporary netrc and point curl at it
# (covered in a later scene)
echo 'Secret never touches the command line this way'

Odczytywanie sekretów ze standardowego wejścia

Najbezpieczniejszym wzorcem interaktywnym jest odczytanie sekretu w czasie działania za pomocą read -rs. Flaga -s wyłącza echo, dzięki czemu wpisywane znaki nigdy nie są wyświetlane, a -r zapobiega interpretacji odwrotnych ukośników.

Najważniejsze informacje:

  • Zmienna nigdy nie jest eksportowana, więc procesy potomne nie mogą zobaczyć jej za pośrednictwem /proc/<pid>/environ.
  • Po użyciu natychmiast wykonaj unset zmiennej, aby skrócić czas jej ekspozycji.
  • Unikaj echo "$SECRET" — używaj printf '%s', aby zapobiec zniekształceniu wartości przez końcowy znak nowej linii i zachować ją niewidoczną w śladach wykonania.
#!/usr/bin/env bash
set -euo pipefail

# Prompt on stderr so stdout stays clean for piping
read -rsp 'Enter API token: ' API_TOKEN <&2
printf '\n' >&2

# Use the secret — printf keeps it out of argv
response=$(printf '%s' "$API_TOKEN" | curl -sS -X POST \
  -H 'Content-Type: application/json' \
  --data-binary @- \
  https://httpbin.org/post 2>/dev/null) || true

echo "Request sent."

# Scrub immediately — unset removes it from shell memory
unset API_TOKEN

Sekrety w plikach: uprawnienia i własność

Gdy sekret musi być przechowywany na dysku (np. klucz konta usługi), uprawnienia pliku są podstawowym zabezpieczeniem.

  • Tryb 0600 — plik może odczytywać i zapisywać wyłącznie właściciel. Brak dostępu dla grupy i innych użytkowników.
  • Tryb 0400 — właściciel ma wyłącznie dostęp do odczytu. Warto używać tego trybu w przypadku kluczy, których nie należy nigdy przypadkowo nadpisać.
  • Pliki z sekretami należy przechowywać w dedykowanym katalogu, takim jak ~/.secrets/ lub /run/secrets/ (ten drugi jest w wielu systemach Linux systemem plików tmpfs opartym na pamięci RAM i istnieje tylko do ponownego uruchomienia systemu).
  • Nie należy nigdy umieszczać plików z sekretami w katalogu śledzonym przez git bez odpowiednio skonfigurowanego pliku .gitignore.
#!/usr/bin/env bash
set -euo pipefail

SECRETS_DIR="${HOME}/.secrets"
mkdir -p "$SECRETS_DIR"
chmod 700 "$SECRETS_DIR"   # directory: only owner can list contents

KEY_FILE="${SECRETS_DIR}/api_token"

# Write secret — atomically restrict permissions before writing content
install -m 0600 /dev/null "$KEY_FILE"
printf '%s' 'my-super-secret-token' > "$KEY_FILE"

echo "Permissions:"
ls -la "$KEY_FILE"

# Read back safely — no subshell, no echo
API_TOKEN=$(< "$KEY_FILE")
echo "Token length: ${#API_TOKEN} chars (value not printed)"
unset API_TOKEN

Używanie pliku .netrc z curl

curl obsługuje plik ~/.netrc (lub dowolną ścieżkę podaną za pomocą --netrc-file), który mapuje nazwy hostów na dane uwierzytelniające. Dzięki temu dane uwierzytelniania są całkowicie nieobecne w wierszu poleceń i treści skryptu.

Format pliku jest prosty:

machine api.example.com
  login admin
  password s3cr3t

Najlepsze praktyki:

  • Zawsze należy ustawić chmod 0600 ~/.netrc — w niektórych systemach curl odrzuca plik dostępny do odczytu dla wszystkich użytkowników.
  • Należy użyć --netrc-file /run/secrets/netrc, aby wskazać sekret przechowywany w tmpfs lub wstrzyknięty do kontenera.
  • Tymczasowe pliki netrc należy usuwać za pomocą trap dla EXIT.
#!/usr/bin/env bash
set -euo pipefail

TMP_NETRC=$(mktemp)
chmod 0600 "$TMP_NETRC"

# Trap ensures cleanup even on error or signal
trap 'rm -f "$TMP_NETRC"' EXIT

# Write credentials to the temp netrc
cat > "$TMP_NETRC" <<'EOF'
machine httpbin.org
  login myuser
  password mypassword
EOF

curl -fsS --netrc-file "$TMP_NETRC" \
  https://httpbin.org/basic-auth/myuser/mypassword \
  -o /dev/null -w 'HTTP %{http_code}\n' || true

# trap fires here: $TMP_NETRC is deleted
echo 'Temp netrc cleaned up by trap.'

Higiena zmiennych środowiskowych

Zmienne środowiskowe są popularnym sposobem wstrzykiwania sekretów do skryptów (aplikacje 12-factor, potoki CI/CD). Są jednak przekazywane do każdego procesu potomnego i przez cały czas działania procesu widoczne w /proc/<pid>/environ.

Wzorce ochronne:

  • Sekret należy natychmiast przypisać do zmiennej lokalnej i usunąć zmienną środowiskową, aby procesy potomne nie mogły jej odziedziczyć.
  • Sekrety należy przekazywać konkretnym poleceniom za pomocą env -i lub przypisania w wierszu polecenia, zamiast przekazywać całe odziedziczone środowisko.
  • Nie należy nigdy używać export dla zmiennej zawierającej sekret — jeśli to możliwe, należy użyć wyłącznie przypisania (bez export).
#!/usr/bin/env bash
set -euo pipefail

# Simulate a secret arriving via environment (e.g., from CI system)
export DB_PASSWORD='hunter2'   # set by CI — we did not choose this

# Capture locally, then strip from environment immediately
db_password="$DB_PASSWORD"
unset DB_PASSWORD

# Verify the env var is gone before spawning any child process
if printenv DB_PASSWORD 2>/dev/null; then
  echo 'ERROR: DB_PASSWORD still in environment!' >&2
  exit 1
fi

echo 'Secret captured and env var scrubbed.'
echo "Password length: ${#db_password}"
unset db_password

Zapobieganie pojawianiu się sekretów w śladach set -x

set -x (xtrace) jest nieocenione podczas debugowania, ale wypisuje wartość każdej rozwijanej zmiennej — również sekretów — na standardowe wyjście błędów. Ślady te często trafiają do dzienników CI lub syslog.

Strategie ochrony sekretów przy zachowaniu użytecznego śledzenia:

  • Na czas operacji wrażliwych należy tymczasowo wyłączyć śledzenie za pomocą { set +x; } 2>/dev/null.
  • Po zakończeniu należy ponownie włączyć śledzenie za pomocą set -x.
  • Wyjście xtrace należy przekierować do osobnego deskryptora pliku prowadzącego do chronionego pliku dziennika, a nie do publicznego strumienia logów.
#!/usr/bin/env bash
set -euo pipefail
set -x   # tracing ON — safe for non-sensitive sections

echo 'Building application...'
SRC_DIR='/tmp/build'
mkdir -p "$SRC_DIR"

# Disable xtrace around secret handling (suppress the set +x line itself)
{ set +x; } 2>/dev/null

read -rsp 'Token (hidden from trace): ' SECRET_TOKEN <&2
printf '\n' >&2
token_len=${#SECRET_TOKEN}
unset SECRET_TOKEN

set -x  # tracing back ON

echo "Token captured (length=$token_len). Continuing build..."
ls "$SRC_DIR"

Usuwanie sekretów z plików dzienników

Nawet przy zachowaniu ostrożności sekrety czasami trafiają do danych wyjściowych dziennika — szczególnie w rozbudowanych lub starszych skryptach. Funkcja opakowująca logowanie, która maskuje znane wzorce, zapewnia dodatkową warstwę ochrony.

Ten wzorzec używa zastępowania opartego na wyrażeniach regularnych dla wszystkich danych wyjściowych dziennika. Jest to warstwa ostatniej szansy, a nie zamiennik innych omówionych już praktyk higieny.

#!/usr/bin/env bash
set -euo pipefail

# A logging function that scrubs common secret patterns before writing
log() {
  local line
  # Replace anything that looks like key=VALUE or password=VALUE
  line=$(printf '%s\n' "$*" \
    | sed -E 's/(password|token|secret|key)=[^[:space:]]*/\1=***REDACTED***/gi')
  printf '[%s] %s\n' "$(date -u '+%T')" "$line"
}

# Usage:
log 'Connecting to database with password=hunter2'
log 'Loaded API token=sk-abc123xyz secret'
log 'Build step completed successfully'   # unchanged

Izolowane środowiska za pomocą env -i

env -i uruchamia polecenie z całkowicie pustym środowiskiem, uniemożliwiając przekazanie do procesu potomnego jakichkolwiek odziedziczonych zmiennych — w tym przypadkowo ujawnionych sekretów. Następnie jawnie przekazuje się tylko to, co jest potrzebne.

Jest to szczególnie przydatne podczas uruchamiania niezaufanych skryptów, narzędzi do budowania lub narzędzi innych firm, które mogą wyprowadzać dane środowiskowe.

#!/usr/bin/env bash
set -euo pipefail

# Polluted parent environment (simulating a CI runner)
export AWS_SECRET_ACCESS_KEY='AKIAIOSFODNN7EXAMPLE'
export GITHUB_TOKEN='ghp_faketoken123'
export HOME="$HOME"
export PATH="$PATH"

echo '--- Child sees full environment:'
env | grep -E 'AWS|GITHUB' | head -5

echo '--- Sanitised child (env -i) sees nothing secret:'
env -i HOME="$HOME" PATH="$PATH" TERM="${TERM:-dumb}" \
  bash -c 'env | grep -E "AWS|GITHUB" || echo "No secrets visible"'

unset AWS_SECRET_ACCESS_KEY GITHUB_TOKEN

Tymczasowe pliki z sekretami w tmpfs

tmpfs to system plików oparty na pamięci RAM. Zapisane tam pliki nigdy nie są opróżniane na dysk, co eliminuje ryzyko, że sekrety pozostaną w pamięci wymiany, pamięci podręcznej dysku lub migawkach.

  • W systemie Linux katalogi /dev/shm i /run/user/<uid> są zwykle punktami montowania tmpfs.
  • Użycie tmpfs należy zawsze połączyć z trap EXIT, aby usuwać pliki po zakończeniu skryptu.
  • W kontenerach (Docker, Kubernetes) sekrety można montować jako woluminy tmpfs bezpośrednio w /run/secrets.
#!/usr/bin/env bash
set -euo pipefail

# Prefer /run/user/$UID (user-owned tmpfs) or /dev/shm (world-readable dir!)
if [[ -d "/run/user/$UID" ]]; then
  TMPFS_DIR="/run/user/$UID"
elif [[ -d '/dev/shm' ]]; then
  TMPFS_DIR='/dev/shm'
else
  # Fallback: warn that disk will be used
  echo 'WARNING: No tmpfs available; using /tmp (disk-backed)' >&2
  TMPFS_DIR='/tmp'
fi

SECRET_FILE=$(mktemp "${TMPFS_DIR}/secret.XXXXXX")
chmod 0600 "$SECRET_FILE"
trap 'shred -u "$SECRET_FILE" 2>/dev/null || rm -f "$SECRET_FILE"' EXIT

printf '%s' 'my-runtime-token' > "$SECRET_FILE"
echo "Secret stored in: $SECRET_FILE"
df -T "$SECRET_FILE" | awk 'NR==2 {print "Filesystem type:", $2}'

# Use the secret...
token=$(< "$SECRET_FILE")
echo "Token length: ${#token}"
unset token
# trap fires on exit: file shredded

Połączenie wszystkich elementów: wzmocniony skrypt wdrożeniowy

Poniższy skrypt łączy wszystkie techniki z tej lekcji w realistyczne narzędzie pomocnicze do wdrażania. Proszę zauważyć, jak każda warstwa ochrony wzmacnia pozostałe:

  • Odczyt ze stdin za pomocą -s — brak echa w terminalu
  • Plik sekretu w tmpfs z czyszczeniem za pomocą trap
  • Czyszczenie środowiska — sekret jest usuwany przed uruchomieniem dowolnego procesu potomnego
  • Ochrona xtrace — śledzenie jest wstrzymywane wokół wrażliwego kodu
  • Redagowanie logów — wyrażenie regularne jako siatka bezpieczeństwa przed zapisaniem do dziennika
#!/usr/bin/env bash
set -euo pipefail

### 1. Redacting logger
log() {
  local msg
  msg=$(printf '%s' "$*" \
    | sed -E 's/(password|token|secret|key)=[^[:space:]]*/\1=***/gi')
  printf '[%s] %s\n' "$(date -u +%T)" "$msg"
}

### 2. tmpfs secret store
TMPFS_DIR="${XDG_RUNTIME_DIR:-/tmp}"
SECRET_FILE=$(mktemp "${TMPFS_DIR}/deploy_token.XXXXXX")
chmod 0600 "$SECRET_FILE"
trap 'rm -f "$SECRET_FILE"; log "Secret file cleaned up."' EXIT

### 3. Read secret without trace
{ set +x; } 2>/dev/null
read -rsp 'Deploy token: ' _tok <&2; printf '\n' >&2
printf '%s' "$_tok" > "$SECRET_FILE"
unset _tok
set -x

### 4. Scrub inherited env vars before subprocess
unset DEPLOY_TOKEN 2>/dev/null || true

log 'Starting deployment...'
# Simulate deploy using secret from file (token never in argv)
# curl -H "Authorization: Bearer $(< $SECRET_FILE)" https://api.example.com/deploy
log 'Deployment complete. token=hidden_by_redactor'

echo 'Done.'

Sprawdzenie wiedzy: ujawnianie sekretów na liście procesów

Sprawdź swoją wiedzę na temat wycieku sekretów przez listy procesów oraz sposobów zapobiegania temu problemowi.

Podsumowanie lekcji: bezpieczne przetwarzanie sekretów

Ukończono lekcję Bezpieczne przetwarzanie sekretów i higiena środowiska. Poniżej znajduje się zwięzłe podsumowanie wszystkich omówionych zagadnień:

  • Listy procesów: Nie należy nigdy przekazywać sekretów jako argumentów wiersza poleceń — pojawiają się w ps aux i /proc/<pid>/cmdline. Zamiast tego należy użyć potoku stdin lub --netrc-file.
  • Odczyt ze stdin: Należy używać read -rs, aby interaktywnie pobierać sekrety bez echa w terminalu i ujawniania ich w historii powłoki.
  • Uprawnienia plików: Pliki z sekretami muszą mieć ustawione chmod 0600 (lub 0400). Do atomowego tworzenia należy używać install -m 0600.
  • Pliki netrc: Dane uwierzytelniające należy przekazywać do pliku tymczasowego wskazanego przez --netrc-file, a następnie usuwać je za pomocą trap EXIT.
  • Higiena środowiska: Po zapisaniu sekretów lokalnie należy natychmiast użyć unset dla odpowiednich zmiennych środowiskowych; nie należy niepotrzebnie używać export; do izolowania procesów potomnych należy używać env -i.
  • Ochrona xtrace: Wrażliwy kod należy umieścić w konstrukcji { set +x; } 2>/dev/null ... set -x, aby zapobiec ujawnianiu wartości w śladach debugowania.
  • Redagowanie logów: Należy używać loggera opartego na sed jako awaryjnej warstwy ochrony.
  • tmpfs: Sekrety używane w czasie działania należy przechowywać w /run/user/$UID lub /dev/shm, aby nigdy nie trafiały na dysk; przy kończeniu działania należy je bezpiecznie usunąć.

Najważniejsze jest podejście oparte na wielowarstwowej ochronie: żaden pojedynczy środek nie jest wystarczający, ale zastosowanie ich razem bardzo utrudnia wyciek sekretów.

Często zadawane pytania

Czy lekcja „Bezpieczne obchodzenie się z sekretami i higiena środowiska” jest bezpłatna?

Tak — pełny tekst „Bezpieczne obchodzenie się z sekretami i higiena środowiska” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Linux Command Line & Bash Scripting Mastery, przejdź na CoddyKit PRO. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Co nauczysz się w „Bezpieczne obchodzenie się z sekretami i higiena środowiska”?

Nie umieszczaj poświadczeń na listach procesów ani w logach, korzystając ze standardowego wejścia, plików i oczyszczonego środowiska. Ćwiczysz Linux Command Line & Bash Scripting Mastery z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Linux Command Line & Bash Scripting Mastery?

Nie wymagamy żadnego doświadczenia. Linux Command Line & Bash Scripting Mastery w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Bezpieczne obchodzenie się z sekretami i higiena środowiska”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Linux Command Line & Bash Scripting Mastery?

Tak. Każda lekcja Linux Command Line & Bash Scripting Mastery zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Zapobieganie wstrzykiwaniu poleceń i argumentów
  2. Bezpieczne obchodzenie się z sekretami i higiena środowiska
  3. Wykonywanie z minimalnymi uprawnieniami i dyscyplina sudo
  4. Analiza statyczna i audyt za pomocą ShellCheck
← Powrót do Linux Command Line & Bash Scripting Mastery