¿Usando cURL con un nombre de usuario y contraseña?

468

Quiero acceder a una URL que requiere un nombre de usuario / contraseña. Me gustaría intentar acceder a él con curl. En este momento estoy haciendo algo como:

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

Me sale un error Supongo que necesito especificar un nombre de usuario y contraseña junto con el comando anterior.

¿Cómo puedo hacer eso?

usuario246114
fuente

Respuestas:

695

Use la -ubandera para incluir un nombre de usuario, y curl le pedirá una contraseña:

curl -u username http://example.com

También puede incluir la contraseña en el comando, pero luego su contraseña será visible en el historial de bash:

curl -u username:password http://example.com
Finbarr
fuente
109
Tenga en cuenta que si hace esto desde la consola, la contraseña permanecerá en el historial que es ... incorrecta Debe especificar solo -u usuario y CURL le pedirá la contraseña en modo sin eco.
Cristian Vrabie
25
@CristianVrabie Técnicamente correcto, pero incorrecto si lo está ejecutando desde un script automatizado que no permite avisos. Sería curioso acerca de una solución a ese problema.
Ligemer
26
@OmarOthman si está ejecutando curl desde un script, las credenciales (obviamente) no terminarán en su historial, pero serán visibles en ps (1). arreglo:print -- '-u username:password' > somewhere && curl -K somewhere http://...
solo alguien
77
Las variables de entorno @Jay se evaluarán antes de la ejecución del comando. La contraseña seguirá siendo visible en la salida ps.
Robert Važan
8
No para diferir el punto, pero creo que mi respuesta ( stackoverflow.com/a/27894407/758174, es decir, usar --netrc-file) es más segura. Mantiene la contraseña fuera del historial, ps, su script, etc. Esa es la única forma que uso en todos mis scripts y para todos los usos autenticados de curl.
Pierre D
255

Es más seguro hacer:

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

... como pasar una cadena de usuario / contraseña simple en la línea de comando, es una mala idea.

El formato del archivo de contraseña es (según man curl):

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

Nota:

  1. ¡El nombre de la máquina no debe incluir https://o similar! Solo el nombre de host.
  2. Las palabras ' machine', ' login' y ' password' son solo palabras clave; La información real es el material después de esas palabras clave.
Pierre D
fuente
10
Sí, eso mantiene la contraseña fuera de la lista de procesos y el historial de comandos. Manera mucho más preferible de hacer esto, y solo un poco más de trabajo :)
AC Capehart
8
Esta definitivamente debería ser la respuesta aceptada; las contraseñas en la línea de comandos son una práctica horrible. (Y este es un hecho ampliamente conocido)
ELLIOTTCABLE
66
También puede usar la bandera -K <file>o --config <file>recibir banderas de rizo a través de un archivo o entrada estándar. (Advertencia: no debe confundirse con -ko --insecure!)
Rufflewind
2
Este método curl mantiene las credenciales fuera del historial y el estado del proceso, pero deja el nombre de usuario y la contraseña en texto sin cifrar en el archivo my-password creando otro vector de ataque, peor que tener información en el archivo del historial: bash, por ejemplo, restringe automáticamente los permisos del archivo de historial. Un problema similar surge si se usan variables de entorno con, por ejemplo, un script para establecer el nombre de usuario / contraseña. Si el script no es seguro, tampoco lo son las credenciales.
Steven el fácilmente divertido el
55
@SteventheEasilyAmused No estoy de acuerdo, es mucho mejor usar un .netrcarchivo de texto sin formato con permisos estrictamente apropiados, de modo que solo su usuario pueda leerlo, que otros mecanismos (por ejemplo, argumentos de línea de comandos) que permiten que otros usuarios lean la información.
Ken Williams
77

O lo mismo pero diferente sintaxis

curl http://username:[email protected]/test/blah?something=123
Daniel Magnusson
fuente
1
Yo uso esa sintaxis, porque se puede usar en muchas más situaciones. Como desde un cmd de Windows sin cURL y sin wGet, usando start "" "http://username:[email protected]/test/blah?something=123". Se puede iniciar desde cualquier lugar. Eso también se aplica a los inicios de sesión ftp; D
m3nda
99
Debes codificar en URL el nombre de usuario y la contraseña para usar caracteres divertidos
diachedelic
2
Sé que la mayoría de las personas saben que no deben enviar contraseñas (o incluso nombres de usuario) en la URL como este ejemplo, ya que es fácil de rastrear. Con eso dicho; No lo recomiendo, pero úsalo solo cuando sepas lo que estás haciendo.
LosManos
1
Esto es muy arcaico y no debe usarse. Esto es de los días FTP: o
Qix - MONICA FUE MALTRATADA el
2
Desafortunadamente, esto deja la contraseña visible en la lista de procesos.
Mark Ribau
63

También puede enviar el nombre de usuario escribiendo:

curl -u USERNAME http://server.example

Curl le pedirá la contraseña, y la contraseña no será visible en la pantalla (o si necesita copiar / pegar el comando).

Kristian
fuente
28

Para pasar de forma segura la contraseña en un script (es decir, evitar que aparezca con ps auxf o logs), puede hacerlo con el indicador -K- (lea la configuración de stdin) y un heredoc:

curl --url url -K- <<< "--user user:password"
Matt Fleming
fuente
2
Gracias por la referencia a la --configopción (-K) ... posiblemente una mejor solución sería poner "--user user: password" en un archivo y simplemente -K the filetener una copia de la contraseña en lugar de una copia en cada script . Mucho más fácil asegurar un solo archivo.
Chris Cogdon
1
Opción similar, en el que sólo la contraseña está en el archivo: cat "${password_filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-. Tuve que poner -K-antes de la url para el viejo macOS bash, YMMV.
Mark Ribau
12

Por lo general, el comando CURL se denomina

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

si no tiene ninguna contraseña o desea omitir el símbolo del sistema para solicitar una contraseña, simplemente deje la sección de contraseña en blanco.

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

Touseef Murtaza
fuente
1
NOTA: La contraseña sería visible en el historial de shell y en la lista de procesos.
Mark Ribau
10
curl -X GET -u username:password  {{ http://www.example.com/filename.txt }} -O
usuario128364
fuente
1
NOTA: La contraseña sería visible en el historial de shell y en la lista de procesos.
Mark Ribau
8

Para que la contraseña no aparezca en tu .bash_history:

curl -u user:$(cat .password-file) http://example-domain.tld
sjas
fuente
66
En este caso, la contraseña seguirá terminando en la lista de procesos, por ejemplo, es visible para alguien que lo haga ps auxw |grep curlen el momento adecuado. Del mismo modo, la contraseña se registrará si se ejecuta a través desudo
Adam Katz
1
Con este método, la contraseña está presente en un archivo (.password-file) que puede ser más inseguro que el historial .bash. Lo bueno de esto es que es solo la contraseña: la URL y el nombre de usuario no se filtran en el archivo .password.
Steven el fácilmente divertido el
7

bastante fácil, haz lo siguiente:

curl -X GET/POST/PUT <URL> -u username:password
Preyas
fuente
No hay requisitos de seguridad en la cuestión
Victor Polo De Gyves Montero
1
NOTA: La contraseña sería visible en el historial de shell y la lista de procesos
Mark Ribau
6

Otras respuestas han sugerido netrc para especificar nombre de usuario y contraseña, de acuerdo con lo que he leído, estoy de acuerdo. Aquí hay algunos detalles de sintaxis:

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

Al igual que otras respuestas, me gustaría enfatizar la necesidad de prestar atención a la seguridad con respecto a esta pregunta.

Aunque no soy un experto, encontré estos enlaces interesantes:

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

Para resumir:

El uso de las versiones encriptadas de los protocolos (HTTPS vs HTTP) (FTPS vs FTP) puede ayudar a evitar la fuga de la red.

Usar netrc puede ayudar a evitar fugas en la línea de comandos.

Para ir un paso más allá, parece que también puede cifrar los archivos netrc usando gpg

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

Con esto, sus credenciales no están "en reposo" (almacenadas) como texto sin formato.

Brian Davis
fuente
5

La forma más simple y sencilla sería utilizar variables de entorno para almacenar / recuperar sus credenciales. Por lo tanto, un comando curl como:

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

Luego llamaría a su API de descanso y pasaría el WWW_Authenticationencabezado http con los valores codificados en Base64 de API_USERy API_HASH. El -Lksimplemente dice rizo seguir http 30x y vuelve a dirigir a utilizar TLS inseguros manipulación (es decir, ignorar los errores SSL). Mientras que el doble --es solo bash syntax sugar para detener el procesamiento de las banderas de línea de comando. Además, las banderas -b cookies.txty -c cookies.txtmanejan las cookies -benviando cookies y -calmacenando cookies localmente.

El manual tiene más ejemplos de métodos de autenticación .

Dwight Spencer
fuente
1
Tenga en cuenta que el uso de "-Lk" puede abrirlo a ataques de hombre en el medio (MITM), así que tenga cuidado con esa opción.
GuyPaddock
44
Esto no funciona ... ya que bash expande esas variables por usted, la expansión aparece en la lista de procesos.
Chris Cogdon
4

La forma más segura de pasar credenciales a curl es que se le solicite que las inserte. Esto es lo que sucede al pasar el nombre de usuario como se sugirió anteriormente ( -u USERNAME).

¿Pero qué pasa si no puede pasar el nombre de usuario de esa manera? Por ejemplo, el nombre de usuario puede necesitar ser parte de la url y solo la contraseña debe ser parte de una carga útil de json.

tl; dr: así es cómo usar curl de forma segura en este caso:

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

read solicitará tanto el nombre de usuario como la contraseña desde la línea de comandos, y almacenará los valores enviados en dos variables que pueden ser referencias en comandos posteriores y finalmente desarmarse.

Voy a explicar por qué las otras soluciones no son ideales.

¿Por qué las variables de entorno no son seguras?

  1. El modo de acceso y exposición del contenido de una variable de entorno no se puede rastrear (ps -eww) ya que el entorno está implícitamente disponible para un proceso
  2. A menudo, las aplicaciones capturan todo el entorno y lo registran con fines de depuración o monitoreo (a veces en archivos de registro de texto sin formato en el disco, especialmente después de que una aplicación falla)
  3. Las variables de entorno se transmiten a procesos secundarios (por lo tanto, se rompe el principio del mínimo privilegio)
  4. Mantenerlos es un problema: los nuevos ingenieros no saben que están allí y no conocen los requisitos que los rodean, por ejemplo, no pasarlos a subprocesos, ya que no se hacen cumplir ni están documentados.

¿Por qué no es seguro escribirlo directamente en un comando en la línea de comando? Porque su secreto termina siendo visible para cualquier otro usuario que se ejecute, ps -auxya que enumera los comandos enviados para cada proceso en ejecución. También porque su secrte termina en el historial de bash (una vez que finaliza el shell).

¿Por qué no es seguro incluirlo en un archivo local? La restricción estricta de acceso POSIX en el archivo puede mitigar el riesgo en este escenario. Sin embargo, todavía es un archivo en su sistema de archivos, sin cifrar en reposo.

iammyr
fuente
2
¿Parece que este método aún mostraría la contraseña en la lista de procesos?
Mark Ribau, el
4

Tenía la misma necesidad en bash (Ubuntu 16.04 LTS) y los comandos proporcionados en las respuestas no funcionaron en mi caso. Tuve que usar:

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

Las comillas dobles en los -Fargumentos solo son necesarias si está utilizando variables, por lo tanto, desde la línea de comando ... -F 'username=myuser' ...estará bien.

Aviso de seguridad relevante: como el Sr. Mark Ribau señala en los comentarios, este comando muestra la contraseña (variable $ PASS, expandida) en la lista de procesos.

Marco
fuente
1
¿Parece que esto todavía muestra el valor de $ PASS en la lista de procesos?
Mark Ribau
Sí, lamentablemente lo hace.
Marco
1

Si está en un sistema que tiene la aplicación Gnome keyring, una solución que evita exponer la contraseña directamente es usar gkeyring.py para extraer la contraseña del llavero:

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
Eliot Blennerhassett
fuente
1
NOTA: La contraseña sería visible en la lista de procesos. (E historia si esto no es parte de un guión.)
Mark Ribau
1

Esto es MUCHO más de lo que solicitó el OP, pero dado que este es un resultado superior para pasar contraseñas de forma segura curl, estoy agregando estas soluciones aquí para otros que llegan aquí buscando eso.


NOTA: -sarg for readcommand no es POSIX, por lo que no está disponible en todas partes, por lo que no se utilizará a continuación. Vamos a utilizar stty -echoy en su stty echolugar.

NOTA: Todas las variables de bash a continuación podrían declararse como locales si están en una función, en lugar de desarmarse.

NOTA: perlgeneralmente está disponible en todos los sistemas que he probado debido a que es una dependencia para muchas cosas, mientras que rubyy pythonno lo está, por lo que lo uso perlaquí. Si puede garantizar ruby/ pythondónde está haciendo esto, puede reemplazar elperl comando con su equivalente.

NOTA: Probado en bash3.2.57 en macOS 10.14.4. Es posible que se requiera una pequeña traducción para otros shells / instalaciones.


Solicite de forma segura a un usuario una contraseña (reutilizable) para pasar a curl. Particularmente útil si necesita llamar a curl varias veces.

Para proyectiles modernos, ¿dónde echoestá incorporado?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

Para los shells más antiguos, ¿dónde echoestá algo así /bin/echo(donde sea que se vea lo que se puede ver en la lista de procesos):
ESTA VERSIÓN NO PUEDE REUTILIZAR LA CONTRASEÑA , vea más abajo en su lugar.

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



Si necesita almacenar la contraseña temporalmente en un archivo, volver a usarla para varios comandos antes de borrarla (por ejemplo, porque está usando funciones para la reutilización de código y no quiere repetir el código y no puede pasar el valor a través de echo). (Sí, estos son un poco artificiales, ya que en este formulario no se encuentran funciones en diferentes bibliotecas; intenté reducirlos al código mínimo necesario para mostrarlo).

Cuando echo está incorporado (esto es especialmente artificial, ya que echo está incorporado, pero se proporciona para completar):

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

Cuando echo es algo como /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
Mark Ribau
fuente