Last Updated: February 05, 2021
· destructuring

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.

9 Responses
Add your response

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!

over 1 year ago ·

{ 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

over 1 year ago ·

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

gpg --batch $PWFILE.gpg
rm -f $PWFILE

curl -sL -k -u user:${PASSWORD} http://.........

over 1 year ago ·

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

over 1 year ago ·

@geezer: well, but -u user:${PASSWORD} is show as user:xxxxx in ps
@ianab: same for $(< password.txt)

over 1 year ago ·

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.

over 1 year ago ·

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.

over 1 year ago ·

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- "" \
  <<<"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)\"") ""
Now STDIN is available to use for supplying the POST data when using the --data @- option.

28 days ago ·

My comment above has a mistake: I should have used cat <<<"..." instead of echo "..."
I refined my answer here:

28 days ago ·