bash 强制 cURL 从环境中获取密码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33794842/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 13:55:07  来源:igfitidea点击:

Forcing cURL to get a password from the environment

bashsecuritycurlenvironment-variablessh

提问by Adam Katz

This question about using cURL with a username and passwordhas suboptimal answers for me:

这个关于使用带有用户名和密码的 cURL 的问题对我来说不是最佳答案:

  1. curl -u "user:pw" https://example.computs the pw in the process list
  2. curl "https://user:[email protected]"puts the pw in the process list
  3. curl -u "user:$(cat ~/.passwd)" https://example.computs the pw in the process list
  4. curl -u user https://example.comprompts for the pw
  5. curl --netrc-file ~/.netrc https://example.comrequires a file
  1. curl -u "user:pw" https://example.com将密码放入进程列表
  2. curl "https://user:[email protected]"将密码放入进程列表
  3. curl -u "user:$(cat ~/.passwd)" https://example.com将密码放入进程列表
  4. curl -u user https://example.com提示输入密码
  5. curl --netrc-file ~/.netrc https://example.com需要一个文件

#4 is secure, but I might run this command hundreds of times a day, so it's tedious. #5 is close to secure, but that file could be read by somebody with root access.

#4 是安全的,但我每天可能会运行这个命令数百次,所以很乏味。#5 接近安全,但该文件可以被具有 root 访问权限的人读取。

The cURL man pagesays (note the bold text):

卷曲手册页说(注意粗体文本):

-u/--user <user:password>

Specify the user name and password to use for server authentication. Overrides -n/--netrcand --netrc-optional.

If you just give the user name (without entering a colon) curl will prompt for a password.

If you use an SSPI-enabled curl binary and do NTLM authentication, you can force curl to pick up the user name and password from your environmentby simply specifying a single colon with this option: -u :.

-u/--user <user:password>

指定用于服务器验证的用户名和密码。覆盖-n/--netrc--netrc-optional

如果您只提供用户名(不输入冒号),curl 将提示输入密码。

如果您使用支持SSPI卷曲二进制并做NTLM身份验证,可以强制卷曲拿起从您的环境中的用户名和密码,通过简单地指定使用此选项单冒号:-u :

I've tried setting $USERand $PASSWORD(and $CURLOPT_PASSWORDand others) in the environment, but cURL doesn't pick up either of them when invoked as curl -u : https://example.com(nor does it work without the -u :).

我已经尝试在环境中设置$USERand $PASSWORD(和$CURLOPT_PASSWORD其他),但是 cURL 在调用时不会选择它们中的任何一个curl -u : https://example.com(如果没有 ,它也不会工作-u :)。

I'm not doing NTLM, so this doesn't work. Unless I'm missing something.

我不是在做 NTLM,所以这行不通。除非我遗漏了什么。

 

 

Is there a way to pass credentials to curlsolely through the environment?

有没有办法curl仅通过环境传递凭据?

 

 

(Workaround moved to an answer)

(解决方法移至答案)

回答by Adam Katz

This bashsolution appears to best fit my needs. It's decently secure, portable, and fast.

bash解决方案似乎最适合我的需求。它非常安全,便携且快速。

#!/bin/bash
SRV="example.com"
URL="https://$SRV/path"
curl --netrc-file <(cat <<<"machine $SRV login $USER password $PASSWORD") "$URL"

This uses process substitution(<( command )runs commandin a sub-shell to populate a file descriptorto be handed as a "file" to the parent command, which in this case is curl). The process substitution contains a here-string(cat <<< text, a variant of echo textthat won't put anything into your process list), creating a file descriptor for the netrc filein order to pass credentials to the remote web server.

此用途进程替换<( command )运行command在子壳填充一个文件描述符被切换为“文件”到父命令,在这种情况下是curl)。进程替换包含一个here-string( cat <<< text,它的一个变体echo text不会将任何内容放入您的进程列表),为netrc 文件创建一个文件描述符,以便将凭据传递给远程 Web 服务器。

The security afforded by process substitution is actually pretty sound: its file descriptor is nota temporary file and is unavailable from even other calls in the same shell instance, so this appears securein this context; an adversary would have to dig through memory or launch a complicated attack to find its contents. Since the $PASSWORDenvironment variable is also in memory, this should not increase the attack surface.

进程替换提供的安全性实际上非常可靠:它的文件描述符不是临时文件,甚至同一个 shell 实例中的其他调用都不可用,因此在这种情况下这看起来是安全的;对手必须挖掘内存或发起复杂的攻击才能找到其内容。由于$PASSWORD环境变量也在内存中,这不应该增加攻击面

As long as you haven't used export PASSWORD, a trick like ps ewwp $$shouldn't reveal the password (as noted in this comment). It'd also be wise to use some less obvious variable name.

只要您还没有使用过export PASSWORD,像这样的技巧就ps ewwp $$不应泄露密码(如本评论中所述)。使用一些不太明显的变量名也是明智的。

Here is a simplified insecure version of the above code that may help explain how it works:

这是上述代码的简化不安全版本,可能有助于解释其工作原理:

#!/bin/sh
# INSECURE VERSION, DO NOT USE
SRV=example.com
URL="https://$SRV/path"
TMP=$(mktemp)
printf "machine %s login %s password %s\n" "$SRV" "$USER" "$PASSWORD" > "$TMP"
curl --netrc-file "$TMP" "$URL"
rm -f "$TMP"

This insecure version has lots of flaws, all of which are solved in the previous version:

这个不安全的版本有很多缺陷,在之前的版本中都解决了:

  • It stores the password in a file (though that file is only readable to you)
  • It very briefly has the password in a command line
  • The temporary file remains until aftercurlexits
  • Ctrl+cwill quit without removing the temporary file
  • 它将密码存储在一个文件中(尽管该文件仅对您可读)
  • 它非常简短地在命令行中有密码
  • 临时文件保留到退出curl
  • Ctrl+c将退出而不删除临时文件

Some of that could be solved by:

其中一些可以通过以下方式解决:

#!/bin/sh
SRV=example.com
URL="https://$SRV/path"
TMP=$(mktemp /dev/shm/.XXXXX)  # assumes /dev/shm is a ramdisk
trap "rm -f $TMP" 0 18
cat << EOF > "$TMP"
machine $SRV login $USER password $PASSWORD
EOF
(sleep 0.1; rm -f "$TMP") &  # queue removing temp file in 0.1 seconds
curl --netrc-file "$TMP" "$URL"

I consider this version to be messy, suboptimal, and possibly less secure (though it is more portable). It also requires a version of sleepthat understands decimals (and 0.1 seconds may be too fast if the system is heavily loaded).

我认为这个版本是凌乱的、次优的,并且可能不太安全(尽管它更便携)。它还需要一个能sleep理解小数的版本(如果系统负载很重,0.1 秒可能太快了)。

 

 



I had originally posted a workaround that included a perlone-liner in my question, then (with help from Etan Reisner) I worked through a few better methods before settling on this here-string method, which is both lighter-weight (faster) and more portable.

我最初发布了一个解决方法,其中perl在我的问题中包含了一个单行,然后(在 Etan Reisner 的帮助下)我尝试了一些更好的方法,然后才确定了这个 here-string 方法,它既轻巧(更快)又更便携。

At this point, it's elegant enough that I'd consider it the "answer" rather than an "ugly workaround," so I've migrated it to be this official answer. I've given @ghotia +1 for his answer, which correctly states that cURL's command line program is incapable of doing what I want on its own, but I'm not "accepting" that answer because it doesn't help solve the issue.

在这一点上,它足够优雅,我认为它是“答案”而不是“丑陋的解决方法”,因此我已将其迁移为官方答案。我已经给了@ghti一个 +1的回答,正确地指出 cURL 的命令行程序无法自己做我想做的事,但我没有“接受”这个答案,因为它无助于解决问题问题。

回答by ghoti

Is there a way to pass credentials to curlsolely through the environment?

有没有办法curl仅通过环境传递凭据?

No, I don't think there is.

不,我认为没有。

The CURLOPT_USERPWDdocumentation I think describes what you need, but this is an option that would be available using the curl library in some other language. PHP, Perl, C, etc.

CURLOPT_USERPWD文档我想介绍你所需要的,但是这是将使用curl库在其他语言可用的选项。PHP、Perl、C 等

The curl binary you run from your shell is just another front end on that library, but the way things like CURLOPT_USERPWD get passed to the library through the curl binary is by use of command line options on the binary.

您从 shell 运行的 curl 二进制文件只是该库的另一个前端,但是通过 curl 二进制文件将 CURLOPT_USERPWD 之类的东西传递给库的方式是使用二进制文件上的命令行选项。

You could theoretically write your own binary as a front end to the curl library, and write in support for environment variables.

理论上,您可以编写自己的二进制文件作为 curl 库的前端,并编写对环境变量的支持。

You could alternately hack environment support as you're hoping to see it into the existing curl binary, and compile your own with local functions.

您也可以 hack 环境支持,因为您希望在现有的 curl 二进制文件中看到它,并使用本地函数编译您自己的。

Beware, though, that even environment variables may be leaked by your shell into the process table. (What do you see when you run ps ewwp $$?)

但是请注意,即使是环境变量也可能被您的 shell 泄漏到进程表中。(你跑步的时候看到了什么ps ewwp $$?)

Perhaps a .netrc file with restricted permissions will be the safest way to go. Perhaps you will need to generate a temporary .netrc file to be used by the --netrc-filecurl option.

也许具有受限权限的 .netrc 文件将是最安全的方法。也许您需要生成一个临时 .netrc 文件以供--netrc-filecurl 选项使用。

I think you either have to pick the least risky solution for your environment, or write something in a real language that does security properly.

我认为您要么必须为您的环境选择风险最低的解决方案,要么用真正的语言编写一些可以正确实现安全性的东西。

回答by sfgeorge

User "Tom, Bom" provides a decent solution for this here: https://coderwall.com/p/dsfmwa/securely-use-basic-auth-with-curl

用户“Tom, Bom”在这里提供了一个不错的解决方案:https: //coderwall.com/p/dsfmwa/securely-use-basic-auth-with-curl

curl --config - https://example.com <<< 'user = "username:password"'

This prevents passwords from showing up in the process list, though this does not specifically address the OP's original question:

这可以防止密码出现在进程列表中,尽管这并没有专门解决 OP 的原始问题:

Is there a way to pass credentials to curl solely through the environment?

有没有办法传递凭据以仅通过环境卷曲?

I still give points to @ghoti for giving a more comprehensive and informative answer.

我仍然对@goti 给予积分,因为他们给出了更全面、更翔实的答案。

回答by grepit

Previous answers are correct, the best option is using -n for curl(assuming you on linux):

以前的答案是正确的,最好的选择是对 curl 使用 -n(假设您在 linux 上):

  1. create a file (use your own favorite editor)
  1. 创建一个文件(使用你自己喜欢的编辑器)

vi ~YOUR_USER_NAME/.netrc

vi ~YOUR_USER_NAME/.netrc

  1. add the followings
  1. 添加以下内容

machine example.com login YOUR_USER_NAME password THE_ACTUAL_PASSWORD

machine example.com login YOUR_USER_NAME password THE_ACTUAL_PASSWORD

  1. run

curl -n https://example.com/some_end_point

curl -n https://example.com/some_end_point