【问题标题】:Using cURL with a username and password?使用带有用户名和密码的 cURL?
【发布时间】:2011-02-05 09:31:36
【问题描述】:

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

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

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

我该怎么做?

【问题讨论】:

    标签: curl credentials


    【解决方案1】:

    使用-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 的所有经过身份验证的用法。
    【解决方案2】:

    这样做更安全:

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

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

    密码文件的格式为(按照man curl):

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

    注意:

    1. 机器名称必须包含https:// 或类似名称!只是主机名。
    2. machine”、“login”和“password”这些词只是关键字;实际信息是这些关键字之后的内容。

    【讨论】:

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

    或相同的东西但语法不同

    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?
    【解决方案4】:

    您也可以直接发送用户名:

    curl -u USERNAME http://server.example
    

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

    【讨论】:

      【解决方案5】:

      要在脚本中安全地传递密码(即防止它出现在 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-。我必须在旧 macOS bash YMMV 的 url 之前加上 -K-
      • 这看起来像是与 Jenkins 一起使用的理想解决方案。
      【解决方案6】:

      通常CURL命令引用为

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

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

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

      【讨论】:

      • 注意:密码将在 shell 历史和进程列表中可见。
      【解决方案7】:
      curl -X GET -u username:password  {{ http://www.example.com/filename.txt }} -O
      

      【讨论】:

      • 注意:密码将在 shell 历史和进程列表中可见。
      【解决方案8】:

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

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

      【讨论】:

      • 问题没有安全要求
      • 注意:密码将在 shell 历史和进程列表中可见
      【解决方案9】:

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

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

      与其他答案一样,我想强调需要注意有关此问题的安全性。

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

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

      总结一下:

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

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

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

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

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

      【讨论】:

        【解决方案10】:

        为了让密码至少不会在你的.bash_history中弹出:

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

        【讨论】:

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

        我在 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 指向 cmets 此命令在进程列表中显示密码($PASS 变量,展开)!

        【讨论】:

        • 看起来这仍然在进程列表中显示 $PASS 的值?
        • 是的,不幸的是。
        • 我收到curl: option -F: is badly used here。卷曲 7.58。你的版本是什么?
        【解决方案12】:

        简单地说,最安全的方法是使用环境变量来存储/检索您的凭据。因此 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 并传递带有 Base64 编码值 API_USERAPI_HASH 的 http WWW_Authentication 标头。 -Lk 只是告诉 curl 遵循 http 30x 重定向并使用不安全的 tls 处理(即忽略 ssl 错误)。而双 -- 只是用于停止处理命令行标志的 bash 语法糖。此外,-b cookies.txt-c cookies.txt 标志处理 cookie,-b 发送 cookie,-c 在本地存储 cookie。

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

        【讨论】:

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

        你可以使用类似的命令,

        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
        【解决方案14】:

        将凭据传递给 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 会在命令行提示输入用户名和密码,并将提交的值存储在两个变量中,这些变量可以在后续命令中引用并最终取消设置。

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

        为什么环境变量不安全

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

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

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

        【讨论】:

        • 这个方法好像还是会在进程列表中显示密码?
        【解决方案15】:

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

        还有其他选择:

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

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

        【讨论】:

          【解决方案16】:

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


          注意:-s arg for read 命令不是 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
          

          【讨论】:

            【解决方案17】:

            如果您使用的是具有 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
            

            【讨论】:

            • 注意:密码将在进程列表中可见。 (如果这不是脚本的一部分,还有历史。)
            【解决方案18】:

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

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

            【讨论】:

              【解决方案19】:

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

              如果是摘要认证,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 选项吗?
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-07-30
              • 1970-01-01
              • 1970-01-01
              • 2018-06-05
              • 1970-01-01
              • 2015-05-18
              • 1970-01-01
              相关资源
              最近更新 更多