【问题标题】:Uploading to Amazon S3 using cURL/libcurl使用 cURL/libcurl 上传到 Amazon S3
【发布时间】:2010-12-02 13:25:18
【问题描述】:

我目前正在尝试开发一个应用程序,以使用 cURL 和 c++ 将文件上传到 Amazon S3 存储桶。仔细阅读 S3 开发人员指南后,我开始使用 cURL 实现我的应用程序并按照开发人员指南的描述形成标题,经过大量试验和错误以确定创建 S3 签名的最佳方式,我现在面临 501 错误.收到的标头表明我正在使用的方法未实现。我不确定我错在哪里,但这是我发送给亚马逊的 HTTP 标头:

PUT /test1.txt HTTP/1.1
Accept: */*
Transfer-Encoding: chunked
Content-Type: text/plain
Content-Length: 29
Host: [BucketName].s3.amazonaws.com 
Date: [Date]
Authorization: AWS [Access Key ID]:[Signature] 
Expect: 100-continue

出于安全原因,我已截断存储桶名称、访问密钥 ID 和签名。

我不确定我做错了什么,但我认为错误是由于 Accept 和 Transfer-Encoding 字段而产生的(不太确定)。所以谁能告诉我我做错了什么或者为什么我会得到 501。

【问题讨论】:

  • 已解决:在我的代码中缺少文件大小的 CURLOPT,现在一切正常

标签: c++ windows curl amazon-s3 libcurl


【解决方案1】:

您可以执行一个 bash 文件。这是一个示例 upload.sh 脚本,您可以将其运行为:sh upload.sh yourfile

#!/bin/bash
file=$1
bucket=YOUR_BUCKET
resource="/${bucket}/${file}"
contentType="application/x-itunes-ipa"
dateValue=`date -R`
stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}"
s3Key=YOUR_KEY_HERE
s3Secret=YOUR_SECRET
echo "SENDING TO S3"
signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${s3Secret} -binary | base64` 
curl -vv -X PUT -T "${file}" \
 -H "Host: ${bucket}.s3.amazonaws.com" \
 -H "Date: ${dateValue}" \
 -H "Content-Type: ${contentType}" \
 -H "Authorization: AWS ${s3Key}:${signature}" \
 https://${bucket}.s3.amazonaws.com/${file}

更多信息:http://www.jamesransom.net/?p=58

http://www.jamesransom.net/?p=58

【讨论】:

  • 谢谢,但这个问题是五年前的问题,正如标签所示,它适用于 Windows。
  • 在 nix 上你可以做 contentType="$(file -b --mime-type "$1")"
【解决方案2】:

自从提出问题后,游戏发生了显着变化,简单的授权标头不再适用,但使用 UNIX shell 脚本执行仍然可行,如下所示。

确保“openssl”和“curl”在命令行中可用。提示:仔细检查 openSSL 参数语法,因为这些可能因工具的不同版本而异;例如openssl sha -sha256 ... 与 openssl sha256 ...

当心,一个额外的换行符或空格字符,否则单独使用 CRLF 代替 NewLine 字符会破坏签名。另请注意,您可能希望使用可能带有编码的内容类型,以防止通过通信媒体进行任何数据转换。然后,您可能需要在多个位置调整签名标头列表;请参阅AMAZON S3 API docs 以了解众多惯例,例如在多个(冗余)位置的哈希计算中使用的标头信息的字母小写排序。

# BERHAUZ Nov 2019 - curl script for file upload to Amazon S3 Buckets
test -n "$1" || {
  echo "usage: $0 <myFileToSend.txt>"
  echo "... missing argument file ..."
  exit
}
yyyymmdd=`date +%Y%m%d`
isoDate=`date --utc +%Y%m%dT%H%M%SZ`
# EDIT the next 4 variables to match your account
s3Bucket="myBucket.name.here"
bucketLocation="eu-central-1" 
s3AccessKey="THISISMYACCESSKEY123"
s3SecretKey="ThisIsMySecretKeyABCD1234efgh5678"

#endpoint="${s3Bucket}.s3-${bucketLocation}.amazonaws.com"
endpoint="s3-${bucketLocation}.amazonaws.com"

fileName="$1"
contentLength=`cat ${fileName} | wc -c`
contentHash=`openssl sha256 -hex ${fileName} | sed 's/.* //'`

canonicalRequest="PUT\n/${s3Bucket}/${fileName}\n\ncontent-length:${contentLength}\nhost:${endpoint}\nx-amz-content-sha256:${contentHash}\nx-amz-date:${isoDate}\n\ncontent-length;host;x-amz-content-sha256;x-amz-date\n${contentHash}"
canonicalRequestHash=`echo -en ${canonicalRequest} | openssl sha256 -hex | sed 's/.* //'`

stringToSign="AWS4-HMAC-SHA256\n${isoDate}\n${yyyymmdd}/${bucketLocation}/s3/aws4_request\n${canonicalRequestHash}"

echo "----------------- canonicalRequest --------------------"
echo -e ${canonicalRequest}
echo "----------------- stringToSign --------------------"
echo -e ${stringToSign}
echo "-------------------------------------------------------"

# calculate the signing key
DateKey=`echo -n "${yyyymmdd}" | openssl sha256 -hex -hmac "AWS4${s3SecretKey}" | sed 's/.* //'`
DateRegionKey=`echo -n "${bucketLocation}" | openssl sha256 -hex -mac HMAC -macopt hexkey:${DateKey} | sed 's/.* //'`
DateRegionServiceKey=`echo -n "s3" | openssl sha256 -hex -mac HMAC -macopt hexkey:${DateRegionKey} | sed 's/.* //'`
SigningKey=`echo -n "aws4_request" | openssl sha256 -hex -mac HMAC -macopt hexkey:${DateRegionServiceKey} | sed 's/.* //'`
# then, once more a HMAC for the signature
signature=`echo -en ${stringToSign} | openssl sha256 -hex -mac HMAC -macopt hexkey:${SigningKey} | sed 's/.* //'`

authoriz="Authorization: AWS4-HMAC-SHA256 Credential=${s3AccessKey}/${yyyymmdd}/${bucketLocation}/s3/aws4_request, SignedHeaders=content-length;host;x-amz-content-sha256;x-amz-date, Signature=${signature}"

curl -v -X PUT -T "${fileName}" \
-H "Host: ${endpoint}" \
-H "Content-Length: ${contentLength}" \
-H "x-amz-date: ${isoDate}" \
-H "x-amz-content-sha256: ${contentHash}" \
-H "${authoriz}" \
http://${endpoint}/${s3Bucket}/${fileName}

我必须承认,对于像我这样有点涉及密码学的人来说,亚马逊签名方案值得众多批评:

  • 签名的信息有很多冗余,
  • 5 步 HMAC 级联几乎颠倒了密钥种子和数据之间的语义,其中 1 步就足以满足正确使用和相同的安全性
  • 密钥的最后 12 个字符在这里没有用处,因为 SHA256 HMAC 的有效密钥长度是 ... 256 位,因此是 32 个字节,其中前 4 个始终以“AWS4”开头,只是没有目的.
  • 整体 AWS S3 API 重新发明了 S/MIME 有效负载可以完成的标准

向批评者道歉,我无法抗拒。但请承认:它运行可靠,对许多公司有用,并且是具有丰富 API 的有趣服务。

【讨论】:

  • 我正在写这篇文章的一半,然后决定再用一组关键字搜索并找到这个答案。到目前为止,这是我得到的最接近的结果,尽管签名方案似乎再次发生了变化,因为亚马逊正在响应“我们计算的请求签名与您提供的签名不匹配”。感谢您为我们其他人解决这个问题!
  • “签名计算不匹配”表示“canonicalRequest”或“stringToSign”与实际 HTTP 标头/数据之间存在差异。对文件路径要非常小心(AWS3 只知道存储桶的 PUT 路径),并且还要考虑请求标头和它们在“canonicalRequest”和“stringToSign”中的列表之间的最严格对齐。使用 curl -v(详细)查看 HTTP 请求中的确切标头和路径。此外,如果您(例如)添加了内容类型,则必须调整和“规范化”“canonicalRequest”和“stringToSign”中的标头列表,如参考文献中的 API 文档中所述。
  • 我收到以下错误:来自 AWS “授权标头格式错误;凭据日期无效。日期与 X-Amz-Date 不同”。这是它的键/值:“x-amz-date: 20201025T020215Z”
  • 我认为(但不确定)根据您的本地机器时区提交 HTTP 请求时插入了“日期”标头,并且此标头值与生成为 x- 的日期冲突amz-date...确保您的机器时间与官方时间充分一致。
  • &lt;Error&gt;&lt;Code&gt;InvalidRequest&lt;/Code&gt;&lt;Message&gt;Missing required header for this request: x-amz-content-sha256&lt;/Message
【解决方案3】:

已解决:在我的代码中缺少文件大小的 CURLOPT,现在一切正常

【讨论】:

  • 什么选项?标题是如何变化的?
  • 我不明白为什么人们会回答“哦,我想通了,但我不会告诉你我做了什么来解决它,即使你花时间试图帮助我出去”详细说明你的解决方案,否则你就是在浪费人们的时间。
  • 此答案没有公开有关用户 Zaid Amir 应用的解决方案的任何解释。看来他是在自言自语。
猜你喜欢
  • 1970-01-01
  • 2013-04-21
  • 1970-01-01
  • 2017-07-07
  • 2017-10-14
  • 1970-01-01
  • 2015-06-25
  • 2021-09-29
  • 2014-06-10
相关资源
最近更新 更多