我想访问一个需要用户名/密码的URL。我想用curl访问它。现在我正在做的事情是:
curl http://api.somesite.com/test/blah?something=123
我得到一个错误。我想我需要在上面的命令中指定用户名和密码。
我该怎么做呢?
我想访问一个需要用户名/密码的URL。我想用curl访问它。现在我正在做的事情是:
curl http://api.somesite.com/test/blah?something=123
我得到一个错误。我想我需要在上面的命令中指定用户名和密码。
我该怎么做呢?
当前回答
简单地说,最安全的方法是使用环境变量来存储/检索凭据。因此,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_USER和API_HASH的Base64编码值传递给http WWW_Authentication头。lk只是告诉curl遵循http 30x重定向并使用不安全的tls处理(即忽略ssl错误)。而double——只是bash语法中停止处理命令行标志的糖。此外,-b cookie .txt和-c cookie .txt标记处理cookie, -b发送cookie, -c本地存储cookie。
手册中有更多认证方法的示例。
其他回答
要让密码至少不弹出在你的.bash_history:
curl -u user:$(cat .password-file) http://example-domain.tld
这比OP要求的要多得多,但由于这是安全传递密码给curl的顶级结果,我在这里添加了这些解决方案,以供其他人到达这里搜索。
注意:-s arg for read命令不是POSIX,所以不是到处都可用,所以下面不使用。我们将使用stty -echo和stty echo代替。
注意:如果在函数中,下面所有bash变量都可以声明为局部变量,而不是不设置。
注意:perl在我尝试过的所有系统上都是可用的,因为它是许多东西的依赖项,而ruby和python不是,所以在这里使用perl。如果你能保证在ruby/python中执行此操作,你可以用它们的等价命令替换perl命令。
注意:在macOS 10.14.4上的bash 3.2.57中测试。其他shell /安装可能需要一些小的转换。
安全地提示用户输入要传递给curl的(可重用的)密码。如果需要多次调用curl,则特别有用。
对于现代shell, echo是内置的(检查通过哪个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
向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将提示从命令行输入用户名和密码,并将提交的值存储在两个变量中,以便在后续命令中引用并最终取消设置。
我将详细说明为什么其他解决方案都不理想。
为什么环境变量不安全
Access and exposure mode of the content of an environment variable, can not be tracked (ps -eww ) since the environment is implicitly available to a process Often apps grab the whole environment and log it for debugging or monitoring purposes (sometimes on log files plaintext on disk, especially after an app crashes) Environment variables are passed down to child processes (therefore breaking the principle of least privilege) Maintaining them is an issue: new engineers don't know they are there, and are not aware of requirements around them - e.g., not to pass them to sub-processes - since they're not enforced or documented.
为什么直接在命令行中输入它是不安全的 因为运行ps -aux的任何其他用户最终都可以看到您的秘密,因为它列出了为每个当前运行的进程提交的命令。 这还因为您的秘密最终会出现在bash历史记录中(一旦shell终止)。
为什么在本地文件中包含它是不安全的 对文件的严格POSIX访问限制可以降低这种情况下的风险。但是,它仍然是文件系统上的一个未加密的文件。
您应该确定身份验证类型。
如果是摘要认证,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'
如果你在一个有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