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>/cmdlinei 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żywajprintf '%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_TOKENSekrety 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_TOKENUż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 s3cr3tNajlepsze 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ą
trapdla 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 -ilub przypisania w wierszu polecenia, zamiast przekazywać całe odziedziczone środowisko. - Nie należy nigdy używać
exportdla zmiennej zawierającej sekret — jeśli to możliwe, należy użyć wyłącznie przypisania (bezexport).
#!/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_passwordZapobieganie 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' # unchangedIzolowane ś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_TOKENTymczasowe 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/shmi/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 shreddedPołą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 auxi/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(lub0400). 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ć
unsetdla 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
sedjako awaryjnej warstwy ochrony. - tmpfs: Sekrety używane w czasie działania należy przechowywać w
/run/user/$UIDlub/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
- Zapobieganie wstrzykiwaniu poleceń i argumentów
- Bezpieczne obchodzenie się z sekretami i higiena środowiska
- Wykonywanie z minimalnymi uprawnieniami i dyscyplina sudo
- Analiza statyczna i audyt za pomocą ShellCheck