Securely use basic auth with curl
Two areas where a plain text password can easily be seen: the http protocol and the host running the web client. Using https addresses plain text over http, but most scripts still supply the password on the command line or in an environment variable. Running "ps auxfwww" will show the command line and environment are available to any local user.
Fortunately, curl lets you configure command line options through stdin. To insecurely pass the --user option to curl:
echo 'user = "defn:password"' | curl -K - https://googles
To avoid generating the password on the command line, let's say the username:password pair is in a file readable only by the user:
{ echo -n 'user = "'; cat password.txt; echo '"'; }
Or it's emitted by a sudo command:
{ echo -n 'user = "'; sudo get-password; echo '"'; }
Any command that emits the password to stdin will do.
Written by Tom, Bom
Related protips
9 Responses
Just a note: On Linux, at least from what I've read and on my own machine only root can see environment variables for all users. Otherwise a user can see their own environment. Your ps command didn't show me any environment info, even as root. I used 'ps -e -o pid,user,cmd e' instead.
Just check out the permissions in /proc/pid/environ. It's set chmod 400
Otherwise, great tip!
-Fletcher
{ echo -n 'user = "'; cat password.txt; echo '"'; } - this one didn't work for me ( and curl :))<br>
I used this syntax to pass the file with the credentials to curl <br>
cat password.txt | sed 's/^/user=":/;s/$/\"/' | curl ... -K
You can also use gpg to encrypt the password and then pass it as a variable to curl:
to encrypt:
gpg -c $FILE
this creates $FILE.gpg - encrypted password.
get password
PWFILE=~/<file>
gpg --batch $PWFILE.gpg
PASSWORD=cat $PWFILE
rm -f $PWFILE
curl -sL -k -u user:${PASSWORD} http://.........
Like goshaf, I couldn't get this to work:
{ echo -n 'user = "'; cat password.txt; echo '"'; }
I found a (simpler?) alternative, which works as long as you're using bash:
curl -u $(< password.txt) https://googles
Thank you for these tips!
The reason the example with cat is not working as it is, is that cat prints out a newline from the file.
By removing the newline, the code will work:
{ echo -n 'user = "'; cat password.txt | tr -d '\n'; echo '"'; }
tr -d '\n' deletes the newline from the (end of the) data.
After a careful read of man curl, it appears that this might actually be the best way:
curl -K curlconfig.cfg http://www.googles
Then you insert this line to curlconfig.cfg (or what ever filename you like):
user = "defn:password"
Works like a charm. Also, you can add other curl options to that file as well as separate lines.
3 things to consider with this tip:
It will fail if username or password contains a double quotation mark "
It precludes the use of STDIN for anything else, such as POST data using --data @-
password.txt cannot have a trailing newline
Refinement #1: Use sed to escape any embedded double quotation marks:
readonly USERNAME=username
readonly PASSWORD='pa ss"wo$rd'
curl -v -K- "https://httpbin.org/basic-auth/username/pa%20ss%22wo%24rd" \
<<<"user: \"$(sed -E 's/"/\\"/g' <<<$USERNAME:$PASSWORD)\""
Refinement #2: Use process substitution instead of STDIN
readonly USERNAME=username
readonly PASSWORD='pa ss"wo$rd'
curl -v -K <(echo -n "user: \"$(sed -E 's/"/\\"/g' <<<$USERNAME:$PASSWORD)\"")
"https://httpbin.org/basic-auth/username/pa%20ss%22wo%24rd"
Now STDIN is available to use for supplying the POST data when using the --data @-
option.
My comment above has a mistake: I should have used cat <<<"..."
instead of echo "..."
I refined my answer here: https://stackoverflow.com/a/66056079