Warum uns das wichtig ist: Wir sind Geonode und verkaufen Proxys. Daher sehen wir sehr viele Befehle, die Anmeldedaten enthalten – oft sowohl ein Proxy-Passwort als auch ein Ziel-Passwort in derselben Zeile. Die wichtigste Warnung, die man gleich zu Beginn anbringen sollte, lautet: Anmeldedaten in einem curl-Befehl landen im Shell-Verlauf, in Prozesslisten und in allem, was Sie in ein Support-Ticket einfügen. Wir haben bereits mehrmals Screenshots erhalten, die aktive Passwörter enthielten. Die unten beschriebene Vorgehensweise „.netrc“ behebt das Problem in etwa einer Minute und kostet nichts; sie gilt gleichermaßen für Proxy-Anmeldedaten, worauf gegen Ende eingegangen wird.
Die grundlegende Syntax
curl -u username:password https://api.example.com/private
Im curl-Handbuch wird -u, --user <user:password>
wie folgt beschrieben: „Geben Sie den Benutzernamen und das Passwort an, die für die Serverauthentifizierung verwendet werden sollen.“
„Basic“ ist das Standardverfahren, daher ist „--basic
“ in der Regel überflüssig. Das Handbuch besagt dies ebenfalls: „Verwenden Sie die HTTP-Basic-Authentifizierung mit dem Remote-Host. Diese Methode ist die Standardeinstellung, und diese Option ist in der Regel sinnlos, es sei denn, Sie verwenden sie, um eine zuvor festgelegte Option zu überschreiben, die eine andere Authentifizierungsmethode festlegt.“
Was tatsächlich über das Netzwerk gesendet wird, ist ein Header:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Das ist „username:password
“ in Base64-Kodierung – kodiert, nicht verschlüsselt. Jeder, der die Anfrage einsehen kann, kann sie in einem Schritt dekodieren. Deshalb entspricht die Basic-Authentifizierung über einfaches HTTP dem Versenden Ihres Passworts im Klartext, und deshalb sollte sie ausschließlich über HTTPS verwendet werden.
Eine syntaktische Einschränkung aus dem Handbuch: „Benutzername und Passwort werden am ersten Doppelpunkt getrennt, was es unmöglich macht, bei dieser Option einen Doppelpunkt im Benutzernamen zu verwenden. Im Passwort ist dies jedoch weiterhin möglich.“ Ein Doppelpunkt im Passwort ist also zulässig; ein Doppelpunkt im Benutzernamen hingegen nicht.
Warum die Befehlszeile der falsche Ort ist
Das Handbuch lässt diesbezüglich keinen Zweifel:
Auf Systemen, auf denen dies funktioniert, verbirgt
curldas angegebene Optionsargument in Prozesslisten. Dies reicht jedoch nicht aus, um Anmeldedaten vor dem möglichen Zugriff durch andere Benutzer auf demselben System zu schützen, da sie vor dem Löschen noch für einen Moment sichtbar sind. Solche sensiblen Daten sollten stattdessen aus einer Datei oder Ähnlichem abgerufen und niemals im Klartext in einer Befehlszeile verwendet werden.
Vier verschiedene Sicherheitslücken, alle real:
Shell-Verlauf. „~/.bash_history“ oder das zsh-Äquivalent, im Klartext, auf unbestimmte Zeit.
Prozesslisten. Für andere Benutzer auf dem Rechner sichtbar während des kurzen Zeitfensters, bevor curl sie löscht.
Protokolle. Alles, was die von einem Skript ausgeführten Befehle aufzeichnet.
Eingefügte Ausgaben. Fehlerberichte, Issue-Tracker, Chat-Nachrichten, Screenshots.
Der letzte Punkt ist in der Praxis am häufigsten anzutreffen und wird am wenigsten beachtet.
Drei sicherere Methoden
1. Lassen Sie curl nach dem Passwort fragen. Geben Sie nur den Benutzernamen ein, und curl fragt interaktiv nach dem Passwort, wobei es dieses ohne Anzeige im Bildschirm einliest:
curl -u username https://api.example.com/private
Es wird nichts gespeichert, nichts protokolliert. Dies ist der richtige Ansatz für alles, was Sie manuell eingeben.
**2. Verwenden Sie eine „.netrc
“-Datei.** Im Handbuch wird „-n, --netrc
“ wie folgt beschrieben: „Lassen Sie curl die .netrc-Datei im Home-Verzeichnis des Benutzers nach Anmeldenamen und Passwort durchsuchen … Bei Verwendung mit HTTP ermöglicht curl die Benutzerauthentifizierung.“
Erstellen Sie die Datei „~/.netrc
“:
machine api.example.com
login myusername
password mypassword
Schränken Sie anschließend die Zugriffsrechte ein, da curl dies nicht für Sie übernimmt – im Handbuch heißt es: „curl gibt keine Fehlermeldung aus, wenn diese Datei nicht über die richtigen Berechtigungen verfügt (sie sollte weder für alle noch für die Gruppe lesbar sein)“:
chmod 600 ~/.netrc
curl -n https://api.example.com/private
Drei nützliche Details aus dem Handbuch: „Die netrc-Datei enthält Anmeldedaten für einen Hostnamen, unabhängig davon, welches Protokoll und welche Portnummer verwendet werden“, sodass ein Eintrag einen Host abdeckt. --netrc-file
„überschreibt alle anderen Methoden zur Ermittlung der Datei“, was für projektbezogene Anmeldedateien praktisch ist. Und seit curl 8.16.0 kann die Umgebungsvariable ``NETRC`
den Dateinamen angeben. Unter Windows werden sowohl ``.netrc
als auch ``_netrc
` im Home-Verzeichnis überprüft, wobei erstere bevorzugt wird.
``--netrc-optional`
` ist die Variante, die die Datei verwendet, falls vorhanden, und keinen Fehler ausgibt, wenn sie fehlt – besser geeignet für Skripte, die in beiden Zuständen ausgeführt werden können.
3. Aus einer Umgebungsvariablen lesen. Wenn eine Datei nicht praktikabel ist, sollte man sie zumindest aus dem Verlauf heraushalten:
read -rs API_PASS
curl -u "myuser:${API_PASS}" https://api.example.com/private
Beachten Sie das „-s
“ bei „read
“, damit das Passwort nicht angezeigt wird. Da es in der Umgebung des Prozesses dennoch sichtbar ist, handelt es sich eher um eine mittelmäßige als um eine gute Option.
Für Skripte lautet die Lösung: „.netrc
“ mit „chmod 600
“. Dies ist die Option, auf die das Handbuch hinweist, und diejenige, die alle oben aufgeführten Sicherheitsrisiken beseitigt.
Basic im Vergleich zu den anderen Verfahren
curl unterstützt mehrere Verfahren, und wenn man weiß, welches welches ist, lässt sich eine gewisse Verwirrung vermeiden.
| Option | Verfahren | Passwort im Datenstrom |
|---|---|---|
--basic | HTTP Basic (Standard) | Base64-kodiert, praktisch im Klartext |
--digest | HTTP Digest | Gehashtes Challenge-Response-Verfahren |
--ntlm | NTLM | Windows-Umgebungen |
--negotiate | SPNEGO / Kerberos | Ticketbasiert |
--anyauth | Automatisch | Hängt von der gewählten Option ab |
--oauth2-bearer | Bearer-Token | Das Token selbst |
Digest wird wie folgt dokumentiert: „Aktivieren Sie die HTTP-Digest-Authentifizierung. Dieses Authentifizierungsschema verhindert, dass das Passwort im Klartext über das Netzwerk übertragen wird. Verwenden Sie diese Option in Kombination mit der normalen Option „--user“, um Benutzername und Passwort festzulegen.“
--anyauth ist die Komfortoption, deren Nachteil im Handbuch klar dargelegt wird: „Die Authentifizierungsmethode wird automatisch ermittelt, und es wird die sicherste Methode verwendet, deren Unterstützung die Remote-Site angibt. Dazu wird zunächst eine Anfrage gesendet und die Antwort-Header überprüft, was möglicherweise einen zusätzlichen Netzwerk-Roundtrip verursacht.“
Ein zusätzlicher Roundtrip pro Anfrage ist bei hohem Datenaufkommen nicht kostenlos. Und es gibt einen konkreten Fehler, vor dem das Handbuch warnt: „Die Verwendung von --anyauth wird nicht empfohlen, wenn Sie Uploads über stdin durchführen, da dies dazu führen kann, dass Daten zweimal gesendet werden müssen und der Client dann in der Lage sein muss, den Vorgang zurückzuspulen. Sollte dies beim Hochladen über stdin erforderlich sein, schlägt der Upload-Vorgang fehl.“
Also: Verwenden Sie --anyauth, wenn Sie wirklich nicht wissen, was der Server erwartet, und geben Sie das Schema an, sobald Sie es kennen.
Bearer-Token werden von den meisten modernen APIs tatsächlich verwendet und haben überhaupt nichts mit Basic-Auth zu tun:
curl --oauth2-bearer "mF_9.B5f-4.1JqM" https://api.example.com/me
Dies entspricht der manuellen Einstellung von Authorization: Bearer .... Beachten Sie, dass ein Bearer-Token selbst die Anmeldeinformationen darstellt – jeder, der es besitzt, kann es verwenden –, weshalb es genauso behandelt werden muss wie ein Passwort.
Die Antwort auswerten
Ein kurzer Diagnoseweg, wenn die Authentifizierung nicht funktioniert.
**401 Unauthorized
** bedeutet, dass der Server Anmeldedaten erwartet oder die von Ihnen gesendeten abgelehnt hat. Die Antwort enthält einen „WWW-Authenticate
“-Header, der das erwartete Schema angibt. Wenn Sie diesen auslesen, müssen Sie nicht raten:
curl -sS -o /dev/null -D - https://api.example.com/private | grep -i www-authenticate
Wenn dort „Digest
“ steht und Sie „Basic“ gesendet haben, ist das Ihre Antwort.
**403 Forbidden
** ist ein anderer Fall und wird oft falsch interpretiert. Sie haben sich erfolgreich authentifiziert, haben aber keine Berechtigung, diese Aktion durchzuführen. Ein Passwortwechsel hilft hier nicht; eine Änderung Ihrer Berechtigungen könnte jedoch Abhilfe schaffen.
**407 Proxy Authentication Required
** bedeutet, dass der Proxy Anmeldedaten verlangt, nicht das Ziel. Ein anderer Header, eine andere Option – darauf gehen wir als Nächstes ein.
**Ein 200
mit einer Anmeldeseite** bedeutet, dass der Endpunkt überhaupt keine HTTP-Authentifizierung verwendet – er nutzt ein Formular und ein Session-Cookie, und -u
hat hier keine Wirkung. Überprüfe den Content-Type
: Wenn du JSON erwartet hast und text/html
erhalten hast, ist dies wahrscheinlich der Grund.
Um zu überprüfen, was Sie tatsächlich gesendet haben:
curl -v -u user:pass https://api.example.com/private 2>&1 | grep -i '^> authorization'
Beachten Sie den Hinweis im Handbuch, dass die ausführliche Ausgabe „sensible Daten enthalten kann, darunter Benutzernamen, Anmeldedaten oder vertrauliche Inhalte“ – schwärzen Sie diese vor der Weitergabe.
Den Header selbst erstellen
Manchmal entspricht -u
nicht Ihren Vorstellungen, und wenn Sie wissen, was dabei tatsächlich entsteht, können Sie die Einschränkungen umgehen.
Wenn der Benutzername einen Doppelpunkt enthält. -u
trennt am ersten Doppelpunkt, sodass ein Benutzername wie service:reader
nicht dargestellt werden kann. Erstellen Sie den Header direkt:
CRED=$(printf '%s' 'service:reader:mypassword' | base64 -w0)
curl -H "Authorization: Basic ${CRED}" https://api.example.com/private
Beachten Sie printf
anstelle von echo
, da letzteres einen Zeilenumbruch anhängt, der in die kodierten Anmeldedaten gelangt und zu einem rätselhaften 401-Fehler führt. Verwenden Sie außerdem base64 -w0
, um Zeilenumbrüche zu vermeiden – GNU base64
bricht standardmäßig bei 76 Zeichen um, und ein Header mit einem eingebetteten Zeilenumbruch gilt als fehlerhafte Anfrage. Unter macOS bricht base64
nicht um, sodass das Flag überflüssig ist.
Wenn Sie die Anmeldedaten aus einem Secret-Manager benötigen. Die meisten Secret-Tools geben ihre Ausgabe über stdout aus, und wenn Sie den Wert in einer Variablen statt in einer Datei speichern, begrenzen Sie dessen Lebensdauer:
TOKEN=$(vault kv get -field=token secret/api)
curl -H "Authorization: Bearer ${TOKEN}" https://api.example.com/me
Wenn Sie den Header in einer Konfigurationsdatei statt im Befehl haben möchten. curl liest Optionen aus ~/.curlrc` ` oder aus einer Datei mit dem Namen -K : `
# api-auth.conf
--user "myuser:mypassword"
--header "Accept: application/json"
curl -K api-auth.conf https://api.example.com/private
`
Schränken Sie die Datei mit chmod 600` ` ein. Dies ist ein sinnvoller Kompromiss, wenn .netrc nicht passt – zum Beispiel, wenn Sie ein Token anstelle von Benutzername und Passwort benötigen.
Ein Hinweis speziell zu ~/.curlrc
. Dies gilt für jeden Curl-Aufruf dieses Benutzers, auch für solche, die Sie nicht selbst geschrieben haben. Wenn Sie dort Anmeldedaten hinterlegen, werden diese an jeden Host gesendet, den ein Skript gerade anfordert. Verwenden Sie für sensible Daten eine benannte Datei mit -K
und behalten Sie ~/.curlrc
für harmlose Standardwerte wie --show-error
und --location
bei.
Die Proxy-Authentifizierung erfolgt separat
Dies ist der Unterschied, der in unserer Support-Warteschlange die meisten Verwirrungen verursacht.
Es können zwei unabhängige Sätze von Anmeldedaten im Spiel sein: einer für den Proxy, einer für das Ziel. Sie verwenden unterschiedliche Header, unterschiedliche Statuscodes und unterschiedliche curl-Optionen.
curl -x http://proxy.example.com:9000 \
--proxy-user proxyuser:proxypass \
-u apiuser:apipass \
https://api.example.com/private
--proxy-user
authentifiziert sich beim Proxy; -u
authentifiziert sich beim Ziel. Wenn man diese verwechselt, erhält man einen 407-Fehler, obwohl man einen 401-Fehler erwartet hat, oder umgekehrt.
Das Proxy-Schema verfügt über parallele Optionen – --proxy-basic
, --proxy-digest
, --proxy-anyauth
, --proxy-negotiate
–, die die zielseitigen Optionen widerspiegeln.
Zwei praktische Hinweise.
Anmeldedaten in der Proxy-URL weisen dasselbe Sicherheitsrisiko auf, plus eines. -x http://user:pass@proxy:9000
speichert das Passwort in der Befehlszeile und in jeder Umgebungsvariablen, die die Proxy-URL enthält – wo http_proxy
typischerweise abgelegt ist. Führen Sie eine Prozent-Kodierung für alle „@
“, „:
“ oder „/
“ im Passwort durch, da der URL-Parser sonst an der falschen Stelle trennt.
Stellen Sie fest, welcher Knoten Sie abgelehnt hat, anstatt zu raten:
„```
curl -sS -o /dev/null -x "$PROXY"
-w 'connect=%{http_connect} status=%{response_code}\n'
https://api.example.com/private
“ „
`connect=407`
“ bedeutet, dass der Proxy Sie abgelehnt hat und das Ziel nie erreicht wurde. „`connect=200 status=401`
“ bedeutet, dass der Proxy funktioniert hat und das Ziel Anmeldedaten verlangt. Zwei unterschiedliche Lösungen.
Und ein Hinweis speziell zur Proxy-Authentifizierung: Viele Anbieter bieten IP-Whitelisting als Alternative zu Benutzername und Passwort an. Wenn Ihre Quelladresse stabil ist, entfallen die Anmeldedaten vollständig aus Ihren Befehlen – das ist die sauberste verfügbare Lösung: keine Datei, keine Umgebungsvariable, nichts, was auslaufen könnte.
Wenn die Website überhaupt keine HTTP-Authentifizierung verwendet
Ein großer Teil der Meldungen „curl basic auth funktioniert nicht“ betrifft Fälle, in denen die Website von vornherein keine HTTP-Authentifizierung verwendet hat.
So lässt sich das feststellen: Rufen Sie die geschützte URL ohne Anmeldedaten auf und sehen Sie sich die Antwort an:
curl -sS -o /dev/null -D - https://example.com/dashboard
Ein „401
“ mit einem „WWW-Authenticate
“-Header bedeutet HTTP-Authentifizierung, und -u
ist das richtige Werkzeug. Ein „200
“, der eine Anmeldeseite zurückgibt, oder ein „302
“, der zu /login
weiterleitet, bedeutet, dass die Website ein Formular und ein Sitzungscookie verwendet – und da hilft auch kein „-u
“, da dieser Header nicht gelesen wird.
Stattdessen das Formular-Login-Muster. Sende die Anmeldedaten an den Login-Endpunkt, behalte die Cookies und verwende sie erneut:
curl -c jar.txt -d "username=ada&password=secret" \
https://example.com/login
curl -b jar.txt https://example.com/dashboard
-c
schreibt ein Cookie, und -b
liest eines aus. Verwende beide bei nachfolgenden Anfragen (-b jar.txt -c jar.txt
), falls der Server das Session-Cookie rotiert, was bei vielen der Fall ist.
Die Komplikation, auf die Sie stoßen werden: CSRF-Token. Die meisten Anmeldeformulare enthalten ein verstecktes Token, das zusammen mit den Anmeldedaten übermittelt werden muss und pro Sitzung generiert wird. Das bedeutet einen zweistufigen Ablauf – das Formular abrufen, das Token extrahieren und es zusammen mit den Cookies aus Schritt eins übermitteln:
TOKEN=$(curl -sS -c jar.txt https://example.com/login \
| grep -o 'name="csrf_token" value="[^"]*"' \
| cut -d'"' -f4)
curl -b jar.txt -c jar.txt \
-d "csrf_token=${TOKEN}" -d "username=ada" -d "password=secret" \
https://example.com/login
Das Durchsuchen und Ausschneiden von HTML ist anfällig und eignet sich lediglich für eine einmalige Diagnose. Für fortlaufende Aufgaben sollten Sie zunächst prüfen, ob der Dienst eine API mit Token-Authentifizierung anbietet – dies ist fast immer der Fall und bedeutet deutlich weniger Aufwand als die Pflege eines eigenen Scrapers für Ihr Anmeldeformular.
Und wenn die Anmeldung JavaScript erfordert, kann „curl“ dies überhaupt nicht ausführen. Das ist keine Einschränkung von „curl“, die man umgehen muss; es ist ein Hinweis darauf, nach dem API-Endpunkt zu suchen, den die Seite selbst aufruft – diesen finden Sie im Netzwerk-Tab Ihres Browsers und können ihn direkt nachbilden.
Häufig gestellte Fragen
Wie verwende ich die Basic-Authentifizierung mit curl?
curl -u username:password URL. „Basic“ ist das Standard-Schema von curl, daher ist --basic überflüssig, es sei denn, Sie überschreiben eine zuvor festgelegte Methode. Verwenden Sie immer HTTPS, da die Basic-Authentifizierung die Anmeldedaten Base64-kodiert, anstatt sie zu verschlüsseln.
Wie stelle ich ein, dass curl nach einem Passwort fragt?
Geben Sie nur den Benutzernamen an: curl -u username URL. curl fragt interaktiv nach dem Passwort und gibt es nicht aus, sodass nichts in Ihren Shell-Verlauf oder in die Prozesslisten gelangt. Dies ist der richtige Ansatz für alles, was von Hand eingegeben wird.
Ist die Basic-Authentifizierung mit curl sicher?
Nur über HTTPS. Die Anmeldedaten werden Base64-kodiert, was leicht rückverwandelbar ist; über einfaches HTTP liegen sie also praktisch im Klartext vor. Über TLS werden sie durch den Transport geschützt, und das verbleibende Risiko besteht darin, wo Sie sie auf Ihrem eigenen Rechner speichern.
Wie speichere ich curl-Anmeldedaten in einer Datei?
Verwende ~/.netrc mit den Zeilen machine, login und password, füge dann chmod 600 hinzu und rufe curl mit -n auf. curl warnt nicht vor falschen Berechtigungen, daher liegt es an dir, diese festzulegen. --netrc-file verweist auf einen alternativen Speicherort, und --netrc-optional verhindert einen Fehler, wenn keine Datei vorhanden ist.
Warum gibt curl den Status 401 zurück, obwohl mein Passwort korrekt ist?
Es gibt mehrere Möglichkeiten: Der Server erwartet ein anderes Schema – überprüfe den Header „WWW-Authenticate“ –, oder der Endpunkt verwendet eine Formular-Anmeldung mit Cookies anstelle der HTTP-Authentifizierung, oder dein Benutzername enthält einen Doppelpunkt, den -u nicht darstellen kann, da er beim ersten Doppelpunkt trennt.
Was ist der Unterschied zwischen 401 und 403?
401 bedeutet, dass Sie nicht authentifiziert sind: keine oder falsche Anmeldedaten. 403 bedeutet, dass Sie sich erfolgreich authentifiziert haben, aber keine Berechtigung für diese Aktion haben. Ein erneuter Versuch mit anderen Anmeldedaten hilft im ersten Fall, nicht jedoch im zweiten.
Wie authentifiziere ich mich mit curl bei einem Proxy?
„--proxy-user user:password“, was unabhängig von „-u“ für das Ziel ist. Ein 407-Status bedeutet, dass der Proxy Anmeldedaten verlangt; ein 401-Status bedeutet, dass das Ziel dies tut. Wenn Ihre Quelladresse stabil ist, fragen Sie stattdessen Ihren Provider nach einer IP-Whitelist – dadurch entfallen die Anmeldedaten in Ihren Befehlen vollständig.
Was bewirkt --anyauth?
Dadurch erkennt curl das vom Server bevorzugte Authentifizierungsschema, indem es eine Anfrage sendet, die Antwort-Header auswertet und sich anschließend mit der sichersten angebotenen Methode authentifiziert. Der Nachteil ist ein zusätzlicher Hin- und Rückweg pro Anfrage, und im Handbuch wird darauf hingewiesen, dass dies beim Hochladen über stdin fehlschlagen kann, da die Daten möglicherweise zweimal gesendet werden müssen.
Fazit
Die Syntax ist im Handumdrehen verstanden: „-u username:password“ – und schon sind Sie authentifiziert, wobei „basic“ als Standard-Authentifizierungsschema von curl verwendet wird. Der Teil, auf den man besonders achten sollte, ist die Angabe des Passworts.
Das Handbuch von curl selbst ist diesbezüglich eindeutig – Anmeldedaten „sollten stattdessen aus einer Datei oder Ähnlichem abgerufen und niemals im Klartext in einer Befehlszeile verwendet werden“ – und die darin beschriebenen Sicherheitsrisiken sind alle real. Der Shell-Verlauf speichert sie auf unbestimmte Zeit, Prozesslisten legen sie kurzzeitig für jeden auf dem Rechner offen, und eingefügte Terminalausgaben haben die unheimliche Fähigkeit, an Orte zu gelangen, die Sie nicht beabsichtigt haben.
Zwei Gewohnheiten beheben das Problem. Geben Sie bei interaktiver Nutzung nur den Benutzernamen ein und lassen Sie curl nach dem Passwort fragen. Bei Skripten speichern Sie die Anmeldedaten in „~/.netrc“ mit „chmod 600“ und verwenden Sie „-n“. Beides dauert nicht länger als das Eintippen des Passworts.
Und behalten Sie die beiden Authentifizierungsebenen im Blick: Ein 401-Fehler kommt vom Zielserver und erfordert „-u“; ein 407-Fehler kommt vom Proxy und erfordert „--proxy-user“. Wenn Ihre Adresse stabil ist, entfernt eine Whitelist die zweite Anmeldeinformation vollständig aus Ihren Befehlen – was der einzig wirklich sichere Ort für ein Geheimnis ist.
