Czy istnieje sposób na przekazanie poufnych danych w bash za pomocą monitu dla dowolnego polecenia?

40

Załóżmy, że użyłem sha1passdo wygenerowania skrótu poufnego hasła w wierszu polecenia. Mogę użyć sha1pass mysecretdo wygenerowania skrótu, mysecretale ma to wadę, która mysecretjest teraz w historii bash. Czy istnieje sposób, aby osiągnąć cel końcowy tego polecenia, unikając ujawniania mysecretzwykłego tekstu, być może za pomocą passwdzachęty w stylu?

Interesuje mnie również uogólniony sposób, aby to zrobić w celu przekazywania wrażliwych danych do dowolnego polecenia. Metoda zmieni się, gdy wrażliwe dane zostaną przekazane jako argument (np. sha1passIn) lub STDIN do jakiegoś polecenia.

Czy istnieje sposób na osiągnięcie tego?


Edycja : To pytanie przyciągnęło wiele uwagi, a poniżej podano kilka dobrych odpowiedzi. Podsumowanie to:

  • Zgodnie z odpowiedzią @ Kusalananda idealnie byłoby, gdyby nigdy nie trzeba było podawać narzędzia ani hasła lub hasła jako argumentu wiersza poleceń. Jest to podatne na kilka sposobów opisanych przez niego, i należy użyć lepiej zaprojektowanego narzędzia, które jest w stanie pobierać tajne dane wejściowe na STDIN
  • Odpowiedź @ vfbsilva opisuje, jak zapobiegać przechowywaniu rzeczy w historii bash
  • Odpowiedź Jonathana opisuje doskonale dobrą metodę osiągnięcia tego celu, o ile program może pobierać swoje tajne dane na STDIN. Jako taki postanowiłem zaakceptować tę odpowiedź. sha1passw moim OP był tylko przykładem, ale dyskusja wykazała, że ​​istnieją lepsze narzędzia, które pobierają dane na STDIN.
  • jak zauważa @R .. w swojej odpowiedzi , użycie interpretacji poleceń dla zmiennej nie jest bezpieczne.

Podsumowując, zaakceptowałem odpowiedź @ Jonathana, ponieważ jest to najlepsze rozwiązanie, biorąc pod uwagę, że masz dobrze zaprojektowany i dobrze działający program do pracy. Chociaż przekazanie hasła lub hasła jako argumentu wiersza polecenia jest zasadniczo niebezpieczne, inne odpowiedzi zapewniają sposoby złagodzenia prostych problemów związanych z bezpieczeństwem.

kemulować
źródło
6
Mało tego: każdy na tym samym komputerze, który ma uprawnienia do wyświetlania listy uruchomionych procesów, może potencjalnie zobaczyć, że sha1pass mysecretjest uruchomiony, a tym samym wiedzieć, co mysecretjest. (Działa to tylko przez kilka sekund, gdy program jest uruchomiony, oczywiście ...)
MathematicalOrchid
@MathematicalOrchid Można tego uniknąć, uruchamiając na prywatnej maszynie wirtualnej. Ale może to być zbyt dużo pracy, aby skonfigurować wygenerowanie tylko jednego hasła ... :-)
Kusalananda
5
@Kusalananda Miałem na myśli bardziej „nigdy nie umieszczaj wrażliwych danych w wierszu poleceń, nawet jeśli wymyślisz, jak wyłączyć historię poleceń” ...
MathematicalOrchid
2
SHA-1 jest przestarzały dla skrótów kluczy lub haseł od kilku lat.
David Foerster,
2
Zauważ, że jeśli w systemie działa demon kontroli, wszystkie polecenia i wszystkie argumenty wszystkich użytkowników są rejestrowane centralnie przez root, więc każdy, kto może uzyskać dostęp do tych dzienników, zobaczy to.
Randall

Odpowiedzi:

20

Jeśli używasz powłoki zshlub bash, użyj opcji -s readwbudowanej powłoki, aby odczytać wiersz z urządzenia końcowego bez jego echa.

IFS= read -rs VARIABLE < /dev/tty

Następnie możesz użyć fantazyjnego przekierowania, aby użyć zmiennej jako stdin.

sha1pass <<<"$VARIABLE"

Jeśli ktokolwiek psucieknie, zobaczy tylko „sha1pass”.

Zakłada się, że sha1passczyta hasło ze standardowego wejścia (w jednym wierszu, ignorując ogranicznik wiersza), gdy nie podano żadnego argumentu.

Jonathan
źródło
Uważam, że ustaliliśmy, że sha1passnie używa on standardowego strumienia wejściowego.
Kusalananda
@Kusalananda Dobra, ale ta metoda będzie działać dla programów, które czytają ze standardowego wejścia.
Jonathan
Zakładając, że narzędzie może wziąć swój tajny wkład do STDIN, jest to rozsądne i bezpieczne rozwiązanie pod względem bezpieczeństwa?
kemulują
Zdecydowałem się przyjąć tę odpowiedź, biorąc pod uwagę, że jest to najlepsze rozwiązanie, biorąc pod uwagę, że masz dobrze zaprojektowany program do pracy. sha1passbył tylko przykładem w mojej OP i zdecydowanie nie był najlepszym wyborem do tego.
kemuluj
1
@cemulate, ... nie jest bezpieczny w linii poleceń . W kontekście heredoc lub herestring (jak w odpowiedzi tutaj), nie jest narażony ps, ale może być zapisany w pliku tymczasowym - jeśli ktoś chce tego uniknąć, sshpass < <(printf '%s\n' "$VARIABLE")może być wzięty pod uwagę (ponieważ printfjest wbudowany, a nie polecenie zewnętrzne, nie jest przekazywane execvi dostępne za pośrednictwem ps).
Charles Duffy,
35

Najlepiej, aby nigdy nie wpisywać hasła jawnego tekstu w wierszu polecenia jako argumentu polecenia. W ten sposób hasło staje się argumentem polecenia, a argumenty wiersza poleceń mogą być widoczne w tabeli procesów za pomocą prostych narzędzi, takich jak psdzienniki kontroli lub zalogowane do nich.

To powiedziawszy, z pewnością istnieją sposoby na ukrycie faktycznego hasła w historii poleceń powłoki.

sha1pass "$( head -n 1 )"

Następnie wpisz hasło i naciśnij Enter. headKomenda używana tutaj przyjąć dokładnie jeden wiersz danych wejściowych i ostatni przełamane, że typ nie będzie część danych, które są przekazywane do sha1pass.

Aby zapobiec powtórzeniu się znaków:

sha1pass "$( stty -echo; head -n 1; stty echo )"

Te stty -echozakręty dowodzenia off echo wpisywanych znaków z na terminalu. Echo jest następnie przywracane za pomocą stty echo.

Aby przekazać standardowe wejście, to ostatnie polecenie może zostać zmienione (zrobiłbyś to, gdyby sha1passzaakceptowano dane na standardowym wejściu, ale wygląda na to, że to konkretne narzędzie ignoruje standardowe wejście):

{ stty -echo; head -n 1; stty echo; } | somecommand

Jeśli potrzebujesz wprowadzania wielowierszowego (powyższe założenie, że należy przekazać jedną linię, bez znaku nowej linii na końcu), zastąp całą headkomendę cati zakończ wprowadzanie (zakładając somecommand, że odczytuje do końca pliku) Ctrl+D( śledzenie, Returnjeśli chcesz wstawić znak nowego wiersza, lub dwa razy, jeśli nie).

Działa to niezależnie od używanej powłoki (pod warunkiem, że była to powłoka Bourne'a lub rc).

Niektóre powłoki mogą powodować, że nie zapisują wpisanych poleceń w swoich plikach historii, jeśli polecenie jest poprzedzone spacją. Zazwyczaj wiąże się to z koniecznością ustawienia HISTCONTROLwartości ignorespace. To jest obsługiwane przez co najmniej bashi kshna OpenBSD, ale nie przez np ksh93lub dash. zshużytkownicy mogą użyć histignorespaceopcji lub ich HISTORY_IGNOREzmiennej do zdefiniowania wzorca do zignorowania.

W powłokach obsługujących czytanie readbez echa znaków na terminalu można również użyć

IFS= read -rs password     # -s turns off echoing in bash or zsh
                           # -r for reading backslashes as-is,
                           # IFS= to preserve leading and trailing blanks
sha1pass "$password"

ale to oczywiście ma ten sam problem z potencjalnym ujawnieniem hasła w tabeli procesów.

Jeśli narzędzie odczytuje ze standardowego wejścia, a powłoka obsługuje „ciągi znaków”, powyższe można zmienić na

IFS= read -rs password
somecommand <<<"$password"

Podsumowanie komentarzy poniżej:

  • Wykonanie polecenia z hasłem podanym w wierszu polecenia, co robi wszystkie powyższe polecenia, z wyjątkiem tego, które przekazuje dane do polecenia, potencjalnie sprawi, że hasło będzie widoczne dla każdego, kto działa psw tym samym czasie. Żadne z powyższych poleceń nie zapisze jednak wpisanego hasła w pliku historii powłoki, jeśli zostanie wykonane z interaktywnej powłoki.

  • Dobrze zachowujące się programy, które czytają hasła w postaci czystego tekstu, robią to, czytając ze swojego standardowego wejścia, z pliku lub bezpośrednio z terminala.

  • sha1pass wymaga hasła w wierszu polecenia, wpisanego bezpośrednio lub przy użyciu zastępowania polecenia.

  • Jeśli to możliwe, użyj innego narzędzia.

Kusalananda
źródło
11
To jest niepoprawne. Wynik rozwinięcia polecenia $(...)będzie częścią wiersza polecenia i będzie widoczny w psdanych wyjściowych, z wyjątkiem systemu z hartowaniem / proc.
R ..
3
@Kusalananda, nawet nadpisanie argumentu argv po rozpoczęciu pozostawia wrażliwe okno, zanim nastąpi nadpisanie; to łagodzenie, a nie naprawa.
Charles Duffy,
5
@Kusalananda, żaden dobrze zaprojektowany program do mieszania haseł nie będzie wymagał wprowadzania w wierszu poleceń, więc warunkowe jest w zasadzie dane - jeśli nie , należy wybrać inne narzędzie.
Charles Duffy,
4
@CharlesDuffy: Narzędzie tutaj wydaje się zasadniczo zepsute. sha1passuruchamianie bez hasła w wierszu poleceń wydaje się dawać wynik bez czytania niczego ... OP musi więc wybrać inne narzędzie.
R ..
8
Ta odpowiedź jest niebezpieczna z punktu widzenia bezpieczeństwa, a jedyną zaletą jest to, że hasło nie pojawia się w historii powłoki, ale tę korzyść łatwiej osiągnąć, umieszczając spację przed poleceniem
Ferrybig
25

Jeśli tak ustawisz HISTCONTROL:

HISTCONTROL=ignorespace

i uruchom polecenie spacją:

~$  mycommand

nie będzie przechowywany w historii.

vfbsilva
źródło
10

Przekaż wrażliwe dane za pomocą potoku lub tutaj:

command_with_secret_output | command_with_secret_input

lub:

command_with_secret_input <<EOF
$secret
EOF

Sekrety są dobrze w (nieeksportowanych) zmiennych powłoki, ale nigdy nie można używać tych zmiennych w wierszach poleceń, tylko w dokumentach tutaj i wewnętrznych elementach powłoki.

Jak zauważył Kusalananda w komentarzu, jeśli wpisujesz polecenia w interaktywnej powłoce, linie, które wprowadzasz dla dokumentu tutaj, zostaną zapisane w historii powłoki, więc wpisanie hasła nie jest bezpieczne, ale nadal powinno być bezpieczne w użyciu zmienne powłoki zawierające sekrety; historia będzie zawierać tekst, $secreta nie wszystko, co zostało $secretrozszerzone.

Korzystanie z rozszerzeń poleceń nie jest bezpieczne :

command_with_secret_input "$(command_with_secret_output)"

ponieważ dane wyjściowe zostaną dołączone do wiersza poleceń i będą widoczne w psdanych wyjściowych (lub ręcznie czytane z / proc), z wyjątkiem systemów z hartowanym / proc.

Przypisanie do zmiennej jest również w porządku:

secret=$(command_with_secret_output)
R ..
źródło
To, czego szukam, to rzeczywiste polecenie, command_with_secret_outputktóre pozwala mi wpisać tajne wyjście. Czy istnieje takie polecenie, które można tutaj zastąpić?
kweulują
Pamiętaj, że wpisanie dokumentu w bash sesji interaktywnej spowoduje zapisanie dokumentu w pliku historii.
Kusalananda
@cemulate: Wystarczy użyć wbudowanej powłoki read, np read -r secret. Więc twój sekret jest w środku $secret. Możesz uruchomić stty przed / po nim, aby ukryć wejście, jeśli chcesz.
R ..
3
@Kusalananda: sha1passwydaje się zasadniczo uszkodzony / nieużywalny / niebezpieczny, ponieważ nie może odczytać hasła ze standardowego pliku lub pliku. Myślę, że do rozwiązania problemu potrzebna jest inna użyteczność.
R ..
1
@cemulate Twój ostatni komentarz do R jest dokładnie na miejscu. Dlatego to nie pomoże. read -rswykona zadanie (jeśli uwzględnisz -rmożliwość posiadania haseł z odwrotnymi ukośnikami), ale wrócisz do potencjalnego pokazania hasła na liście procesów (i w zależności od tego, czy rozliczanie procesów jest włączone i jak to skonfigurowano , także w dziennikach rozliczania procesu).
Kusalananda
6

Po prostu wpisz wartość do pliku i przekaż plik:

$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass 

Nie jestem pewien, jak to sha1passdziała, jeśli można pobrać plik jako dane wejściowe, możesz użyć sha1pass < mysecret. Jeśli nie, używanie catmoże być problemem, ponieważ zawiera ostatnią nową linię. W takim przypadku użyj (jeśli headobsługuje -c):

head -c-1 mysecret | sha1pass 
terdon
źródło
2
Po co pisać hasło na dysk w swoim pierwszym przykładzie, skoro możesz to zrobić cat | sha1pass? cat mysecret | sha1passi sha1pass < mysecretzachowują się tak samo w odniesieniu do końcowych nowych linii. catnie dodaje nowych linii. W każdym razie, jeśli sha1passobsługuje przekazywanie hasła za pomocą standardowego wejścia, oczekiwałbym, że zignoruje ono samą ostatnią linię. Pliki z liniami, które nie są zakończone znakami nowej linii, są jednak w Uniksie nienaturalne, więc byłoby dziwnie oczekiwać, że plik, który nie jest zakończony znakiem nowego wiersza.
JoL
@JoL i) ponieważ nie myślałem o tym: / Ale jak to zadziała? cat | sha1passwydaje się działać, sha1passzanim daje mi szansę na wprowadzenie jakichkolwiek danych wejściowych. ii) Nie, oczywiście, cat mysecretże nie dodaje nowej linii, nigdy nie powiedziałem cat, że ją dodaje, tylko że zawiera .
terdon
Rozumiem, ale to też nie jest tak, < mysecretże go usuwa. :)
JoL
Nieważne. Po ponownym przeczytaniu widzę, że powiedziałeś to, aby później się oświadczyć head -c-1. Chyba właśnie się pomyliłem, dlaczego używam, cat mysecret | sha1passa potem proponuję sha1pass < mysecret. Myślę, że martwi Cię to, że sha1pass może narzekać na zwykłe pliki dla standardowego wejścia; Nie jestem pewien dlaczego.
JoL
@JoL to więcej, ponieważ nigdy nie korzystałem sha1passi nie mogłem znaleźć instrukcji ani -hżadnej innej formy dokumentacji w ciągu kilku minut, które spędziłem na wyszukiwaniu, więc nie mogłem dowiedzieć się, czy działa sha1pass footraktowany foojak ciąg wejściowy czy plik wejściowy . Dlatego dałem opcje radzenia sobie z każdą możliwością.
terdon
1

Jeśli to, co zrobił terdon, jest możliwe, to jest to najlepsze rozwiązanie, przechodząc przez standardowe dane wejściowe. Pozostał tylko problem, że zapisał hasło na dysk. Zamiast tego możemy to zrobić:

stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo

Jak powiedział Kusalananda, stty -echozapewnia , że to, co piszesz, nie będzie widoczne, dopóki nie stty echopowtórzysz. head -1otrzyma jeden wiersz ze standardowego wejścia i przekaże go do sha1pass.

JoL
źródło
0

użyłbym

sha1pass "$(cat)"

catbędzie czytać ze standardowego do EOF, co może być spowodowane naciśnięciem Ctrl + D. Następnie wynik zostanie przekazany jako argument dosha1pass

oktupol
źródło
3
Odpowiedź R. wyjaśnia, dlaczego jest to niebezpieczne.
hvd