Jak przekazać hasło do procesu potomnego?

18

Przekazywanie hasła w wierszu poleceń (do procesu potomnego rozpoczętego z mojego programu) jest znane jako niebezpieczne (ponieważ może być widoczne nawet przez innych użytkowników za pomocą polecenia ps). Czy zamiast tego można przekazać ją jako zmienną środowiskową?

Czego jeszcze mogę użyć, aby go przekazać? (Z wyjątkiem zmiennej środowiskowej) najłatwiejszym rozwiązaniem wydaje się użycie potoku, ale to najłatwiejsze rozwiązanie nie jest łatwe.

Programuję w Perlu.

porton
źródło
2
Dlaczego to nie jest łatwe? Nie musi to być osobna / nazwana rura, wystarczy zwykłe wejście / wyjście ... to nie powinno stanowić większego problemu w żadnym języku. Możesz umieścić go w zwykłym pliku konfiguracyjnym, jeśli możesz upewnić się, że jest on czytelny tylko w interesujących procesach (co jest o wiele trudniejsze niż się wydaje).
frostschutz
1
Jeśli nie zadzwonisz do exec u dziecka, nadal masz kopię hasła bez potrzeby robienia czegokolwiek.
James Youngman

Odpowiedzi:

26

Argumenty procesu są widoczne dla wszystkich użytkowników, ale środowisko jest widoczne tylko dla tego samego użytkownika ( przynajmniej w Linuksie i myślę, że w każdym nowoczesnym wariancie uniksowym). Dlatego przekazanie hasła przez zmienną środowiskową jest bezpieczne. Jeśli ktoś może odczytać zmienne środowiskowe, może wykonywać procesy tak jak Ty, więc gra już się skończyła.

Zawartość środowiska jest narażona na ryzyko wycieku pośredniego, na przykład jeśli biegniesz, psaby coś zbadać i przypadkowo skopiować i wkleić wynik, w tym poufne zmienne środowiskowe w miejscu publicznym. Innym ryzykiem jest to, że przekazujesz zmienną środowiskową do programu, który jej nie potrzebuje (w tym potomków procesu, który potrzebuje hasła) i że program ujawnia swoje zmienne środowiskowe, ponieważ nie spodziewał się, że będą poufne. Jak złe są te ryzyka wtórnego wycieku, zależy od tego, co robi proces z hasłem (jak długo trwa? Czy działa podprocesy?).

Łatwiej jest upewnić się, że hasło nie wycieknie przypadkowo, przekazując je przez kanał, który nie jest przeznaczony do podsłuchiwania, np. Potok. Jest to dość łatwe po stronie wysyłającej. Na przykład, jeśli masz hasło w zmiennej powłoki, możesz to zrobić

echo "$password" | theprogram

jeśli theprogramoczekuje hasła na swoim standardowym wejściu. Zauważ, że jest to bezpieczne, ponieważ echojest wbudowane; nie byłoby bezpieczne z zewnętrznym poleceniem, ponieważ argument byłby ujawniony w psdanych wyjściowych. Innym sposobem na osiągnięcie tego samego efektu jest dokument tutaj:

theprogram <<EOF
$password
EOF

Niektóre programy wymagające hasła mogą zostać poproszone o odczytanie go z określonego deskryptora pliku. Możesz użyć deskryptora pliku innego niż standardowe wejście, jeśli potrzebujesz standardowego wejścia do czegoś innego. Na przykład z gpg:

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

Jeśli nie można nakazać programowi odczytu z deskryptora pliku, ale można go odczytać z pliku, możesz nakazać mu odczytanie z deskryptora pliku, używając nazwy pliku takiej jak `/ dev / fd / 3.

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

W ksh, bash lub zsh możesz zrobić to bardziej zwięźle poprzez podstawienie procesu.

theprogram --password-from-file=<(echo "$password")
Gilles „SO- przestań być zły”
źródło
Na Solarisie 9 i starszych /usr/ucb/psbył setuid root, więc mógł odczytywać i wyświetlać zmienne środowiskowe innych procesów - zostało to usunięte w Solarisie 10, więc powyższa odpowiedź na „każdy inny współczesny wariant Unixa” dotyczy wydań Solaris od 2005 roku i późniejszych.
alanc
@alanc Rzeczywiście, obecnie nie uważam Solaris <10 za nowoczesny. Solaris 9 jest prawie tak stary jak Windows XP!
Gilles 'SO - przestań być zły'
Gilles: są dni, kiedy ciężko mi się zastanowić, czy Solaris 10 jest nowoczesny, odkąd Solaris 11 został wydany ponad 5 lat, więc całkowicie rozumiem i zgadzam się, ale niestety wiem, że niektórzy ludzie nadal korzystają z Solaris 8 lub 9.
alanc
10

Zamiast przekazywać hasło bezpośrednio przez argument lub zmienną środowiskową

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

użyj tego samego argumentu lub zmiennej środowiskowej, aby przekazać nazwę pliku :

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

Następnie można przejść albo zwykły plik uprawnień chronionych (mimo, że nie chroni cię od innych procesów uruchomionych w ramach tego samego użytkownika), albo /dev/stdini rura to w (który AFAIK uchroni cię od innych procesów uruchomionych w ramach tego samego użytkownika):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

Jeśli użyjesz /dev/stdintutaj, konieczne jest , aby to była fajka . Jeśli jest to terminal, będzie on czytelny dla innych procesów działających pod tym samym użytkownikiem.

Jeśli już musisz użyć swojego /dev/stdindo czegoś innego, możesz użyć podstawienia procesu, jeśli korzystasz z powłoki, która go obsługuje, co zasadniczo jest równoważne z używaniem potoków:

./passwd_receiver <(echo PASSWORD)

Nazwane potoki (FIFO) mogą wyglądać tak samo, ale można je przechwycić.

Te rozwiązania również nieidealnie bezpieczne , ale mogą być wystarczająco blisko, pod warunkiem, że nie używasz systemu z ograniczoną pamięcią, który często się zmienia.

Idealnie byłoby czytać te pliki (potok jest również plikiem) do pamięci oznaczonej mlock (2) jako nie do wymiany, co zazwyczaj robią programy do obsługi haseł, takie jak gnupg.

Uwagi:

  1. Przekazywanie numerów skryptów plików jest teoretycznie tak samo dobre jak plik, jak przekazywanie nazw plików, ale nazwy plików są bardziej praktyczne, ponieważ <()daje nazwę pliku, a nie numer pliku (i coprocs daje ci pliki skryptów oznaczone FD_CLOEXEC , co sprawia, że ​​te pliki nie nadają się do użytku w tym kontekście).

  2. Jeśli korzystasz z systemu Linux, w którym
    /proc/sys/kernel/yama/ptrace_scopejest ustawiona 0opcja AFAIK, nie ma kuloodpornego sposobu ochrony przed innymi procesami działającymi pod tym samym użytkownikiem (mogą użyć ptrace, aby podłączyć się do twojego procesu i odczytać pamięć)

  3. Jeśli potrzebujesz tylko trzymać hasło z dala od procesów uruchomionych przez różnych użytkowników (innych niż root), wówczas wystarczą argumenty, zmienne środowiskowe, potoki i pliki chronione uprawnieniami.

PSkocik
źródło
7

Nie, zmienne środowiskowe są również łatwe do odczytania i przeciekają do procesów potomnych. przekazać go za pomocą rury.

Jasen
źródło
2
„zmienne środowiskowe… przeciek do procesów potomnych” Taki jest sens używania zmiennej środowiskowej. Byłyby bezużyteczne, gdyby nie zostały odziedziczone. „zmienne środowiskowe są również łatwe do odczytania”, nie, nie są.
Patrick
2
Przeczytaj zmienną, usuń ją. To nie jest trudne. I możesz użyć tego samego argumentu na temat potoku. Jeśli potok nie zostanie odczytany, zostanie przekazany do procesu potomnego, a proces potomny może go odczytać i uzyskać hasło.
Patrick
1
@Patrick Udokumentowane środki rozbrajania zmiennych środowiskowych nie muszą szorować wartość od miejsca psi /procmożna go zobaczyć.
zwol
1
Czy jakiś system pozwala odczytać zmienne środowiskowe dowolnych procesów? Nie sądzę, aby Linux zezwalał na procesy należące do innych, a jeśli jesteś tym samym użytkownikiem, możesz po prostu ptrace()cel i odczytać jego pamięć.
ilkkachu
5
Ta odpowiedź jest zła. Zmienne środowiskowe nie mogą być odczytywane przez innych użytkowników.
Gilles „SO- przestań być zły”
1

Jeśli nic innego nie pasuje, rozważ usługę Linux Key Retention (klucze jądra).

Zacznij od: security / keys.txt . Jeden z domyślnych kluczy można sklonować między procesami nadrzędnymi i podrzędnymi.

To nie jest najprostsze rozwiązanie, ale istnieje i wydaje się być utrzymane i używane (było również zamieszane w błąd Androida w zeszłym roku).

Nie wiem o jego statusie „politycznym”, ale miałem podobną potrzebę i zacząłem pracować nad wiążącym podstępem. Nie spotkałem wcześniej istniejącego wsparcia dla Perla.

kzurell
źródło