ChatGPT解决这个技术问题 Extra ChatGPT

使用带有用户名和密码的 cURL?

我想访问需要用户名/密码的 URL。我想尝试使用 curl 访问它。现在我正在做类似的事情:

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

我得到一个错误。我想我需要在上面的命令中指定用户名和密码。

我怎样才能做到这一点?


t
the Tin Man

使用 -u 标志包含用户名,curl 将提示输入密码:

curl -u username http://example.com

您还可以在命令中包含密码,但是您的密码将在 bash 历史记录中可见:

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

请注意,如果您从控制台执行此操作,密码将保留在历史记录中,这是......错误的。您应该只指定 -u 用户,CURL 会在无回显模式下询问您的密码。
@CristianVrabie 技术上正确,但如果您从不允许提示的自动脚本运行它,则不正确。会好奇这个问题的解决方案。
@OmarOthman 如果您从脚本运行 curl,则凭据(显然)不会出现在您的历史记录中,但它们将在 ps(1) 中可见。修复:print -- '-u username:password' > somewhere && curl -K somewhere http://...
@Jay 环境变量将在命令执行之前进行评估。密码在 ps 输出中仍然可见。
不赘述这一点,但我相信我的答案(stackoverflow.com/a/27894407/758174 即使用 --netrc-file)更安全。它将密码排除在历史记录、ps、您的脚本等之外。这是我在所有脚本中使用的唯一形式以及 curl 的所有经过身份验证的用法。
T
Trenton McKinney

这样做更安全:

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

...在命令行上传递一个普通的用户/密码字符串是一个坏主意。

密码文件的格式是(根据 man curl):

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

笔记:

机器名称不得包含 https:// 或类似名称!只是主机名。 “机器”、“登录”和“密码”这些词只是关键字;实际信息是那些关键字之后的东西。


是的,这将密码排除在进程列表和命令历史记录之外。更可取的方式来做到这一点,只需要多做一点工作:)
这绝对应该是公认的答案;命令行上的密码是一种可怕的做法。 (这是一个众所周知的事实。)
您还可以使用标志 -K <file>--config <file> 通过文件或标准输入接收 curl 标志。 (警告:不要与 -k--insecure 混淆!)
此 curl 方法将凭据保留在历史记录和进程状态之外,但在 my-password-file 中以明文形式保留用户名和密码,从而创建另一个攻击媒介 - 比在历史记录文件中包含信息更糟糕:例如,bash 会自动限制权限的历史文件。如果使用环境变量和脚本来设置用户名/密码,也会出现类似的问题。如果脚本不安全,则凭据也不安全。
@SteventheEasilyAmused 我不同意,使用具有适当严格权限的明文 .netrc 文件要好得多,因此只有 your 用户可以读取它,而不是其他允许 的机制(例如命令行参数)其他 用户阅读信息。
D
Daniel Magnusson

或相同的东西但语法不同

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

我使用这种语法,因为可以在更多情况下使用。就像来自没有 cURL 和 wGet 的 Windows cmd 一样,使用 start "" "http://username:password@api.somesite.com/test/blah?something=123"。它可以从任何地方启动。这也适用于 ftp 登录;D
您需要对用户名和密码进行 URL 编码以使用有趣的字符
我知道大多数人都知道不要像这个例子一样在 URL 中发送密码(甚至用户名),因为它很容易被嗅探。照这样说;我不会不推荐它,但仅在您知道自己在做什么时才使用。
不幸的是,这会使密码在进程列表中可见。
@MarkRibau 如果您使用 -u 参数,它不会显示在进程列表中。 curl的巧妙技巧:-)。见How does curl protect a password from appearing in ps output?
K
Kristian

您也可以通过以下方式发送用户名:

curl -u USERNAME http://server.example

然后,Curl 会要求您输入密码,并且密码将不会在屏幕上显示(或者如果您需要复制/粘贴命令)。


M
Matt Fleming

要在脚本中安全地传递密码(即防止它出现在 ps auxf 或日志中),您可以使用 -K- 标志(从标准输入读取配置)和 heredoc:

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

感谢您对 --config 选项 (-K) 的引用...可能更好的解决方案是将“--user user:password”放入文件中,然后只需 -K the file,这样您就只有一个密码副本而是每个脚本中的副本。保护单个文件要容易得多。
类似的选项,文件中只有密码:cat "${password_filepath}" | sed -e "s/^/-u ${username}:/" | curl --url "${url}" -K-。我必须将 -K- 放在旧 macOS bash YMMV 的 url 之前。
这看起来像是与 Jenkins 一起使用的想法解决方案。
如果密码在文件中,则无需使用 sed:echo "-u user:$(cat passwordfile)"|curl -K- url
T
Touseef Murtaza

通常 CURL 命令称为

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

如果您没有任何密码或想跳过命令提示符以要求输入密码,请将密码部分留空。

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


注意:密码将在 shell 历史记录和进程列表中可见。
B
Bugs
curl -X GET -u username:password  {{ http://www.example.com/filename.txt }} -O

注意:密码将在 shell 历史记录和进程列表中可见。
p
pushkin

很简单,请执行以下操作:

curl -X GET/POST/PUT <URL> -u username:password

该问题没有安全要求
注意:密码将在 shell 历史和进程列表中可见
B
Brian Davis

根据我的阅读,其他答案建议 netrc 指定用户名和密码,我同意。以下是一些语法细节:

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

像其他答案一样,我想强调需要注意这个问题的安全性。

虽然我不是专家,但我发现这些链接很有见地:

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

总结一下:

使用协议的加密版本(HTTPS 与 HTTP)(FTPS 与 FTP)有助于避免网络泄漏。

使用 netrc 可以帮助避免命令行泄漏。

更进一步,您似乎还可以使用 gpg 加密 netrc 文件

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

有了这个,您的凭据就不会“静止”(存储)为纯文本。


链接已损坏
s
sjas

要让密码至少不会在您的 .bash_history 中弹出:

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

在这种情况下,密码仍然会出现在进程列表中,例如,在正确的时间执行 ps auxw |grep curl 的人可以看到它。同样,如果通过 sudo 运行,密码将被记录
使用这种方法,密码会出现在一个文件(.password-file)中,该文件可能比 .bash 历史记录更不安全。这样做的好处是,它只是密码 - URL 和用户名不会在 .password 文件中泄露。
M
Marco

我在 bash(Ubuntu 16.04 LTS)中也有同样的需求,而答案中提供的命令在我的情况下不起作用。我不得不使用:

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

只有在使用变量时才需要在 -F 参数中使用双引号,因此从命令行 ... -F 'username=myuser' ... 就可以了。

相关安全注意事项:作为注释中的 Mr. Mark Ribau 点,此命令在进程列表中显示密码($PASS 变量,展开)!


看起来这仍然在进程列表中显示 $PASS 的值?
是的,不幸的是它确实如此。
我得到curl: option -F: is badly used here。卷曲 7.58。你的版本是什么?
D
Deepak R

您可以使用类似的命令,

curl -u user-name -p http://www.example.com/path-to-file/file-name.ext > new-file-name.ext

然后将触发 HTTP 密码。

参考:http://www.asempt.com/article/how-use-curl-http-password-protected-site


链接坏了。
-p 代表 --proxytunnel - 具有误导性,但在其他方面是正确的:“-u ...如果您只是指定用户名,curl 将提示输入密码。” curl.se/docs/manpage.html
B
Benjamin W.

简单地说,最安全的方法是使用环境变量来存储/检索您的凭据。因此 curl 命令如下:

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

然后将调用您的 restful api 并传递带有 API_USERAPI_HASH 的 Base64 编码值的 http WWW_Authentication 标头。 -Lk 只是告诉 curl 遵循 http 30x 重定向并使用不安全的 tls 处理(即忽略 ssl 错误)。而双 -- 只是停止处理命令行标志的 bash 语法糖。此外,-b cookies.txt-c cookies.txt 标志通过 -b 发送 cookie 和 -c 在本地存储 cookie 来处理 cookie。

该手册有更多examples of authentication方法。


请记住,使用“-Lk”可能会使您面临中间人 (MITM) 攻击,因此请谨慎使用该选项。
这不起作用......因为 bash 为您扩展了这些变量,所以扩展出现在进程列表中。
i
iammyr

将凭据传递给 curl 的最安全方法是提示插入它们。这就是在传递之前建议的用户名 (-u USERNAME) 时发生的情况。

但是,如果您不能以这种方式传递用户名怎么办?例如,用户名可能需要是 url 的一部分,并且只有密码是 json 有效负载的一部分。

tl;博士:这是在这种情况下安全使用 curl 的方法:

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

read 将从命令行提示输入用户名和密码,并将提交的值存储在两个变量中,这些变量可以在后续命令中引用并最终取消设置。

我将详细说明为什么其他解决方案不理想。

为什么环境变量不安全

环境变量内容的访问和公开模式,无法跟踪(ps -eww),因为环境对进程隐式可用 通常应用程序会抓取整个环境并将其记录下来以用于调试或监视目的(有时在日志文件中以明文形式显示)在磁盘上,特别是在应用程序崩溃后)环境变量被传递给子进程(因此打破了最小特权原则)维护它们是一个问题:新工程师不知道它们在那里,也不知道周围的需求- 例如,不要将它们传递给子流程 - 因为它们没有被强制执行或记录。

为什么直接在命令行中将其键入命令是不安全的因为您的密钥最终会被运行 ps -aux 的任何其他用户看到,因为它列出了为每个当前运行的进程提交的命令。还因为您的 secrte 最终会出现在 bash 历史记录中(一旦 shell 终止)。

为什么将其包含在本地文件中不安全 对文件的严格 POSIX 访问限制可以减轻这种情况下的风险。但是,它仍然是您文件系统上的一个文件,在静止时未加密。


好像这个方法还是会在进程列表中显示密码?
另一个答案也错过了使用“读取”命令。这触及了我在此页面上的精髓。为什么不在您的帖子中添加以下行:“read -p "Username: " U; curl -u "$U" ; unset U"
h
hamid bayat

在某些 API 中它可能不起作用(如 rabbitmq)。

有替代方案:

curl http://username:password@example.com

curl http://admin:123456@example.com

上述格式也可在浏览器中使用。


R
Raimo

您可以像这样使用带有 curl 的 gpg 加密 netrc 文件:

netrc_file="$HOME/netrc.gpg"
curl --netrc-file <(gpg -d $netrc_file) https://...

M
Mark Ribau

这比 OP 要求的要多得多,但由于这是安全地将密码传递给 curl 的最佳结果,因此我在此处为其他到达此处搜索的人添加了这些解决方案。

注意:read 命令的 -s arg 不是 POSIX,因此并非在任何地方都可用,因此不会在下面使用。我们将改用 stty -echostty echo

注意:如果在函数中,下面的所有 bash 变量都可以声明为局部变量,而不是取消设置。

注意:perl 在我尝试过的所有系统上都非常普遍,因为它是许多事物的依赖项,而 rubypython 不是,所以在这里使用 perl。如果您可以保证在 ruby/python 中执行此操作,则可以将 perl 命令替换为等效命令。

注意:在 macOS 10.14.4 上的 bash 3.2.57 中测试。其他外壳/安装可能需要一些小的翻译。

安全地提示用户输入(可重复使用的)密码以传递给 curl。如果您需要多次调用 curl 则特别有用。

对于现代 shell,其中 echo 是内置的(通过 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

对于较旧的 shell,其中 echo 类似于 /bin/echo(可以在进程列表中看到它的回显):
此版本不能重用密码,请参阅下方。

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

如果您碰巧需要将密码临时存储到文件中,以便在清除之前将其重新用于多个命令(比如因为您正在使用代码重用函数并且不想重复代码并且不能通过 echo 传递值)。 (是的,这些看起来有点做作,不是不同库中的函数;我试图将它们减少到显示它所需的最少代码。)

当 echo 是内置时(这是特别做作的,因为 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'
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

当 echo 类似于 /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

E
Eliot Blennerhassett

如果您在具有 Gnome 密钥环应用程序的系统上,避免直接暴露密码的解决方案是使用 gkeyring.py 从密钥环中提取密码:

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

注意:密码将在进程列表中可见。 (如果这不是脚本的一部分,还有历史。)
B
BREMI

就我而言,我需要一个提示,用户可以在其中输入他们的凭据。

获取用户名和密码提示的最简单方法是以下单行:

read -p "Username: " U ; curl -u "$U" <URL> ; unset U

read 命令提示输入用户名。 -u "$U" 参数告诉 curl 尝试使用用户名 $U 进行身份验证并提示输入密码。

作为奖励,密码仅对 curl 可见,并且不会出现在任何日志或历史记录中。

curl 的手册页有更多关于不同身份验证模式的详细信息:https://curl.se/docs/manpage.html

我也喜欢用户“iammyr”采用的方法。它可以覆盖 cURL 的认证算法失败的情况:
https://stackoverflow.com/a/56130884/1239715


M
Martin

如果您的服务器支持 Basic 身份验证,您可以执行以下操作:

printf 'header="Authorization: Basic %s"' "$(base64 --wrap=0 credentials)"|
curl --config - https://example.org

credentials 将是您以 username:password 形式存储用户名和密码的文件。

此解决方案的好处:

无需转义特殊字符

适用于任何密码,即使它包含空格、引号、反斜杠或其他特殊字符,因此它也可以在您不控制输入的脚本中安全使用

在带有内置 printf 的 shell 中,登录数据不会显示在进程列表中

如果您的 shell 没有 printf 作为内置命令,您可以执行以下操作以避免登录数据出现在进程列表中:

{ printf 'header="Authorization: Basic '; base64 --wrap=0 credentials; printf '"'; }|
curl --config - https://example.org

L
LiuMeng

您应该确定什么是身份验证类型。

如果是摘要认证,http头是:

GET /xxxxxxxxxxx HTTP/1.1
Host: 192.168.3.142
User-Agent: Go-http-client/1.1
Authorization: Digest username="admin", realm="admin@51200304-49-test", nonce="5.1722929000077545", uri="/xxxxxxxxxxx", response="52d30eba90820f2c4fa4d3292a4a7bbc", cnonce="f11900fe0906e3899e0cc431146512bb", qop=auth, nc=00000001
Accept-Encoding: gzip

您可以使用 --digest 选项:

    curl  --digest -u 'username:password' 'http://xxxxxxxxxxx'

您能补充一下为什么需要 --digest 选项吗?