Używasz cURL z nazwą użytkownika i hasłem?


466

Chcę uzyskać dostęp do adresu URL, który wymaga nazwy użytkownika / hasła. Chciałbym spróbować uzyskać do niego dostęp za pomocą curl. Teraz robię coś takiego:

curl http://api.somesite.com/test/blah?something=123

Dostaję błąd Chyba muszę podać nazwę użytkownika i hasło wraz z powyższym poleceniem.

Jak mogę to zrobić?

Odpowiedzi:


693

Użyj -uflagi, aby dołączyć nazwę użytkownika, a curl poprosi o podanie hasła:

curl -u username http://example.com

Możesz także dołączyć hasło do polecenia, ale wtedy twoje hasło będzie widoczne w historii bash:

curl -u username:password http://example.com

109
Pamiętaj, że jeśli zrobisz to z konsoli, hasło pozostanie w historii, co jest ... złe. Powinieneś określić tylko -u użytkownik, a CURL poprosi o hasło w trybie bez echa.
Cristian Vrabie,

25
@CristianVrabie Technicznie poprawne, ale niepoprawne, jeśli uruchamiasz go ze skryptu automatycznego, który nie zezwala na podpowiedzi. Byłby ciekawy rozwiązania tego problemu.
Ligemer,

26
@OmarOthman, jeśli używasz curl ze skryptu, poświadczenia (oczywiście) nie znajdą się w twojej historii, ale będą widoczne w ps (1). fix:print -- '-u username:password' > somewhere && curl -K somewhere http://...
tylko ktoś

7
@Jay Zmienne środowiskowe zostaną ocenione przed wykonaniem polecenia. Hasło będzie nadal widoczne na wyjściu ps.
Robert Važan,

8
Nie chcę tu pochwalać, ale uważam, że moja odpowiedź ( stackoverflow.com/a/27894407/758174, tj. Używanie --netrc-file) jest bezpieczniejsza. Trzyma hasło poza historią, ps, twoim skryptem itp. Jest to jedyna forma, której używam we wszystkich moich skryptach i dla wszystkich uwierzytelnionych zastosowań curl.
Pierre D,

252

Bezpieczniej jest robić:

curl --netrc-file my-password-file http://example.com

... ponieważ przekazywanie zwykłego ciągu użytkownika / hasła w wierszu poleceń jest złym pomysłem.

Format pliku hasła to (zgodnie z man curl):

machine <example.com> login <username> password <password>

Uwaga:

  1. Nazwa maszyny nie może zawierać https://lub podobna! Tylko nazwa hosta.
  2. Słowa „ machine”, „ login” i „ password” to tylko słowa kluczowe; rzeczywiste informacje są po słowach kluczowych.

10
Tak, to utrzymuje hasło poza listą procesów i historią poleceń. Zdecydowanie lepszy sposób, aby to zrobić, i tylko trochę więcej pracy :)
AC Capehart

8
To zdecydowanie powinna być zaakceptowana odpowiedź; hasła w wierszu poleceń są okropną praktyką. (I to jest powszechnie znany fakt.)
ELLIOTTCABLE

6
Możesz także użyć flagi -K <file>lub --config <file>otrzymać flagi curl za pomocą pliku lub standardowego wejścia. (Ostrzeżenie: nie należy mylić z -klub --insecure!)
Rufflewind 19.04.16

2
Ta metoda curl utrzymuje poświadczenia poza historią i statusem procesu, ale pozostawia nazwę użytkownika i hasło w postaci jawnego tekstu w pliku moje hasło, tworząc kolejny wektor ataku - gorszy niż posiadanie informacji w pliku historii: na przykład bash automatycznie ogranicza uprawnienia pliku historii. Podobny problem powstaje, gdy używa się zmiennych środowiskowych np. Ze skryptu do ustawiania nazwy użytkownika / hasła. Jeśli skrypt nie jest bezpieczny, nie ma też poświadczeń.
Steven the Easy Amused

5
@SteventheEasilyAmused nie zgadzam się, że o wiele lepiej jest użyć tekstem jawnym .netrcplik z odpowiednio ścisłymi prawami, więc tylko Twój użytkownik może go czytać, niż inne mechanizmy (np args linii komend), które pozwalają innych użytkowników odczytać te informacje.
Ken Williams

76

Lub ta sama rzecz, ale inna składnia

curl http://username:password@api.somesite.com/test/blah?something=123

1
Używam tej składni, ponieważ może być używana w wielu innych sytuacjach. Jak z Windowsa cmd bez cURL i bez wGet, używając start "" "http://username:password@api.somesite.com/test/blah?something=123". Można go uruchomić z dowolnego miejsca. Dotyczy to także loginów ftp; D
m3nda

8
Musisz użyć
kodu

2
Wiem, że większość ludzi wie, aby nie wysyłać haseł (a nawet nazw użytkowników) w adresie URL, tak jak w tym przykładzie, ponieważ łatwo jest wąchać. Powiedziawszy to; Nie polecam tego, ale używam go tylko wtedy, gdy wiesz, co robisz.
LosManos

1
Jest to archaiczny suuuuuper i nie należy go używać. To pochodzi z dni FTP: o
Qix - MONICA BYŁ SZYBKO ZAKOŃCZONY

2
Niestety pozostawia to hasło widoczne na liście procesów.
Mark Ribau,

63

Możesz również wysłać nazwę użytkownika, pisząc:

curl -u USERNAME http://server.example

Curl poprosi Cię o hasło, a hasło nie będzie widoczne na ekranie (lub jeśli będziesz musiał skopiować / wkleić polecenie).


27

Aby bezpiecznie przekazać hasło w skrypcie (tj. Zapobiec wyświetlaniu się go przy pomocy ps auxf lub logów), możesz to zrobić z flagą -K- (czytaj konfigurację ze standardowego wejścia) i heredoc:

curl --url url -K- <<< "--user user:password"

2
Dzięki za odniesienie do --configopcji (-K) ... być może lepszym rozwiązaniem byłoby umieszczenie w pliku „--user user: password” i po prostu -K the fileposiadanie tylko jednej kopii hasła zamiast kopii w każdym skrypcie . Znacznie łatwiej zabezpieczyć pojedynczy plik.
Chris Cogdon

1
Podobna opcja, gdzie tylko hasło znajduje się w pliku: cat "${password_filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-. Musiałem umieścić -K-przed adresem URL starego basha dla systemu macOS, YMMV.
Mark Ribau,

12

Zwykle polecenie CURL określa się jako

curl https://example.com\?param\=ParamValue -u USERNAME:PASSWORD

jeśli nie masz hasła lub chcesz pominąć wiersz polecenia, aby poprosić o hasło, po prostu pozostaw pole hasła puste.

to znaczy curl https://example.com\?param\=ParamValue -u USERNAME:


1
UWAGA: Hasło będzie widoczne w historii powłoki i liście procesów.
Mark Ribau,


8

Aby hasło nie wyświetlało się w .bash_history:

curl -u user:$(cat .password-file) http://example-domain.tld

6
W takim przypadku hasło nadal znajdzie się na liście procesów, np. Jest widoczne dla kogoś, kto robi to ps auxw |grep curlwe właściwym czasie. Podobnie hasło zostanie zarejestrowane, jeśli zostanie uruchomione przezsudo
Adam Katz,

1
Dzięki tej metodzie hasło jest następnie obecne w pliku (.password-file), co może być bardziej niebezpieczne niż historia .bash. Zaletą tego jest to, że jest to tylko hasło - adres URL i nazwa użytkownika nie są wyciekane w pliku .password-file.
Steven the Easy Amused


6

Inne odpowiedzi sugerują, że netrc określa nazwę użytkownika i hasło, w oparciu o to, co przeczytałem, zgadzam się. Oto kilka szczegółów składni:

https://ec.haxx.se/usingcurl-netrc.html

Podobnie jak inne odpowiedzi, chciałbym podkreślić potrzebę zwrócenia uwagi na bezpieczeństwo w odniesieniu do tego pytania.

Chociaż nie jestem ekspertem, uważam te linki za wnikliwe:

https://ec.haxx.se/cmdline-passwords.html

Podsumowując:

Korzystanie z zaszyfrowanych wersji protokołów (HTTPS vs HTTP) (FTPS vs FTP) może pomóc uniknąć wycieku sieci.

Korzystanie z netrc może pomóc uniknąć wycieku z wiersza poleceń.

Aby pójść o krok dalej, wydaje się, że możesz także szyfrować pliki netrc za pomocą gpg

https://brandur.org/fragments/gpg-curl

Dzięki temu twoje poświadczenia nie są „w spoczynku” (przechowywane) jako zwykły tekst.


5

Najprościej i najprościej najbezpieczniej byłoby użyć zmiennych środowiskowych do przechowywania / odzyskiwania danych uwierzytelniających. Zatem polecenie zwijania, takie jak:

curl -Lk -XGET -u "${API_USER}:${API_HASH}" -b cookies.txt -c cookies.txt -- "http://api.somesite.com/test/blah?something=123"

Następnie wywołałby Twój spokojny interfejs API i przekazał WWW_Authenticationnagłówek http z zakodowanymi wartościami Base64 wartości API_USERi API_HASH. Po -Lkprostu mówi curl, aby śledził przekierowania http 30x i używał niepewnej obsługi tls (tj. Ignorował błędy ssl). Podczas gdy double --to tylko bash cukier składniowy, aby zatrzymać przetwarzanie flag wiersza poleceń. Ponadto flagi -b cookies.txti -c cookies.txtobsługują pliki cookie z -bwysyłaniem plików cookie i -clokalnym przechowywaniem plików cookie.

Podręcznik zawiera więcej przykładów metod uwierzytelniania .


1
Pamiętaj, że użycie „-Lk” może otworzyć cię na ataki typu man-in-the-middle (MITM), więc zachowaj ostrożność przy tej opcji.
GuyPaddock,

4
To nie działa ... ponieważ bash rozszerza te zmienne, rozwinięcie pojawia się na liście procesów.
Chris Cogdon


4

Najbezpieczniejszym sposobem przekazywania poświadczeń do zwijania jest monit o ich wprowadzenie. Tak się dzieje po przekazaniu nazwy użytkownika, jak sugerowano wcześniej ( -u USERNAME).

Ale co jeśli nie możesz przekazać nazwy użytkownika w ten sposób? Na przykład nazwa użytkownika może być częścią adresu URL, a tylko hasło należy do ładunku Json.

tl; dr: Oto jak bezpiecznie używać curl w tym przypadku:

read -p "Username: " U; read -sp "Password: " P; curl --request POST -d "{\"password\":\"${P}\"}" https://example.com/login/${U}; unset P U

read wyświetli monit o podanie zarówno nazwy użytkownika, jak i hasła z wiersza poleceń, i zapisze przesłane wartości w dwóch zmiennych, które mogą być odniesieniami w kolejnych poleceniach, a na końcu zostaną cofnięte.

Omówię, dlaczego inne rozwiązania nie są idealne.

Dlaczego zmienne środowiskowe są niebezpieczne?

  1. Tryb dostępu i ekspozycji zawartości zmiennej środowiskowej nie może być śledzony (ps -eww), ponieważ środowisko jest domyślnie dostępne dla procesu
  2. Często aplikacje przechwytują całe środowisko i logują je w celu debugowania lub monitorowania (czasami w postaci plików tekstowych na dysku, zwłaszcza po awarii aplikacji)
  3. Zmienne środowiskowe są przekazywane do procesów potomnych (dlatego łamanie zasady najmniejszych uprawnień)
  4. Utrzymanie ich jest problemem: nowi inżynierowie nie wiedzą, że tam są, i nie są świadomi wymagań wokół nich - np. Nie przekazują ich do podprocesów - ponieważ nie są one egzekwowane ani dokumentowane.

Dlaczego wpisywanie go bezpośrednio w wierszu polecenia jest niebezpieczne, ponieważ Twój sekret jest następnie widoczny dla każdego innego uruchomionego użytkownika, ps -auxponieważ zawiera listę poleceń przesłanych dla każdego aktualnie uruchomionego procesu. Także dlatego, że twoja secrte kończy się w historii bash (po zakończeniu powłoki).

Dlaczego umieszczenie go w pliku lokalnym jest niebezpieczne Ścisłe ograniczenie dostępu do pliku POSIX może zmniejszyć ryzyko w tym scenariuszu. Jest to jednak nadal plik w systemie plików, niezakodowany w spoczynku.


2
Wydaje się, że ta metoda nadal pokazywałaby hasło na liście procesów?
Mark Ribau,

4

Miałem taką samą potrzebę w bash (Ubuntu 16.04 LTS), a polecenia podane w odpowiedziach nie działały w moim przypadku. Musiałem użyć:

curl -X POST -F 'username="$USER"' -F 'password="$PASS"' "http://api.somesite.com/test/blah?something=123"

Podwójne cudzysłowy w -Fargumentach są potrzebne tylko wtedy, gdy używasz zmiennych, więc z wiersza poleceń ... -F 'username=myuser' ...będzie dobrze.

Ważne informacje dotyczące bezpieczeństwa: jak wskazuje Mark Ribau w komentarzach, polecenie to pokazuje hasło (zmienna $ PASS, rozwinięta) na liście procesów!


1
Wygląda na to, że nadal pokazuje wartość $ PASS na liście procesów?
Mark Ribau,

Tak, niestety tak jest.
Marco

1

Jeśli korzystasz z systemu z aplikacją kluczy Gnome, rozwiązaniem, które pozwala uniknąć bezpośredniego ujawnienia hasła, jest użycie pliku gkeyring.py w celu wyodrębnienia hasła z klucza :

server=server.example.com
file=path/to/my/file
user=my_user_name
pass=$(gkeyring.py -k login -tnetwork -p user=$user,server=$server -1)

curl -u $user:$pass ftps://$server/$file -O

1
UWAGA: Hasło będzie widoczne na liście procesów. (I historia, jeśli nie jest to część scenariusza.)
Mark Ribau,

1

To DUŻO więcej, niż wymagał PO, ale ponieważ jest to najlepszy wynik dla bezpiecznego przekazywania haseł curl, dodam te rozwiązania tutaj dla innych, którzy przyjeżdżają tutaj, szukając tego.


UWAGA: -sarg dla readpolecenia nie jest POSIX, więc nie jest dostępny wszędzie, więc nie będzie używany poniżej. Użyjemy stty -echoi stty echozamiast tego.

UWAGA: Wszystkie poniższe zmienne bash mogą być zadeklarowane jako lokalne, jeśli są w funkcji, a nie są rozbrojone.

UWAGA: perljest dość ogólnie dostępny na wszystkich systemach, które wypróbowałem, ponieważ jest zależny od wielu rzeczy, podczas gdy rubyi pythonnie są, więc używaj perltutaj. Jeśli możesz zagwarantować ruby/ pythongdzie to robisz, możesz zastąpić perlpolecenie ich odpowiednikiem.

UWAGA: Przetestowano w bash3.2.57 na macOS 10.14.4. Niektóre małe tłumaczenia mogą być wymagane w przypadku innych powłok / instalacji.


Bezpiecznie poproś użytkownika o podanie hasła (wielokrotnego użytku) w celu zwijania. Jest to szczególnie przydatne, jeśli trzeba wywoływać curl wiele razy.

W przypadku nowoczesnych powłok, w których echojest wbudowany (sprawdź przez which echo):

url='https://example.com'
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
read pass
printf "\n" # we need to move the line ahead
stty echo   # re-enable echoing user input
echo ${pass} | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-
unset username
unset pass

Dla starszych powłok, gdzie echojest coś takiego /bin/echo(gdzie cokolwiek echo można zobaczyć na liście procesów):
TA WERSJA NIE MOŻE PONOWNIE UŻYĆ HASŁA , patrz niżej.

url='https://example.com'
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
perl -e '
    my $val=<STDIN>;
    chomp $val;
    print STDERR "\n";  # we need to move the line ahead, but not send a newline down the pipe
    print $val;
' | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-
stty echo   # re-enable echoing user input
unset username



Jeśli potrzebujesz tymczasowo zapisać hasło do pliku, użyj go ponownie dla wielu poleceń przed jego wyczyszczeniem (powiedz, ponieważ używasz funkcji do ponownego użycia kodu i nie chcesz powtarzać kodu i nie możesz przekazać wartość przez echo). (Tak, są nieco wymyślone, patrząc w tej formie, nie będąc funkcjami w różnych bibliotekach; Próbowałem zredukować je do minimalnego kodu potrzebnego do jego wyświetlenia.)

Gdy echo jest wbudowane (jest to szczególnie wymyślone, ponieważ echo jest wbudowane, ale zapewnia kompletność):

url='https://example.com'
filepath="$(mktemp)"  # random path, only readable by current user
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
read pass
echo "${pass}" > "${filepath}"
unset pass
printf "\n" # we need to move the line ahead
stty echo   # re-enable echoing user input

cat "${filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-

rm "${filepath}"  # don't forget to delete the file when done!!
unset username

Kiedy echo jest jak /bin/echo:

url='https://example.com'
filepath="$(mktemp)"  # random path, only readable by current user
printf "Username: "
read username
printf "Password: "
stty -echo  # disables echoing user input, POSIX equivalent for 'read -s'
$(perl -e '
    my $val=<STDIN>;
    chomp $val;
    open(my $fh, ">", $ARGV[0]) or die "Could not open file \"$ARGV[0]\" $\!";
    print $fh $val;
    close $fh;
' "$filepath")
printf "\n" # we need to move the line ahead
stty echo   # re-enable echoing user input

cat "${filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-

rm "${filepath}"  # don't forget to delete the file when done!!
unset username
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.