Java 中的 Amazon S3 策略签名

发布于 2024-12-25 06:49:58 字数 1829 浏览 1 评论 0原文

由于某种原因,我在为 Amazon S3 上传策略生成签名方面遇到困难。我发誓我曾经有过这个工作,但现在不再工作了。任何帮助将不胜感激。我需要一双新的眼睛。

Amazon S3 Signature Tester 的输出进行比较时,我不是获得相同的签名。但是,当我直接使用该工具中的签名时,一切正常。所以问题肯定出在我的签名过程中。此外,从该工具中出来的“要签名的字符串”十六进制解码与我正在签名的输入策略相同。

AWS 文档说构建策略签名的过程应该进行像这样:

  1. 使用 UTF-8 对策略进行编码。
  2. 使用 Base64 对这些 UTF-8 字节进行编码。
  3. 使用 HMAC SHA-1 使用您的秘密访问密钥签署策略。
  4. 使用 Base64 对 SHA-1 签名进行编码。

看起来很简单。唯一含糊不清的地方可能是#3。 AWS 文档显示用于生成 HMAC-SHA1 的示例代码段,这是与 我见过的其他 Java 加密示例

我正在使用 Base64 的 Apache Commons 实现 v1.6。我的签名代码基本上如下所示:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/* ... */

private static final String UTF8 = "UTF-8";
private static final String HMACSHA1 = "HmacSHA1";

public static String sign(String secret, String data) {
    byte[] dataBytes = data.getBytes(UTF8);
    byte[] secretBytes = secret.getBytes(UTF8);

    SecretKeySpec signingKey = new SecretKeySpec(secretBytes, HMACSHA1);

    Mac mac = Mac.getInstance(HMACSHA1);
    mac.init(signingKey);
    byte[] signature = mac.doFinal(dataBytes);

    return Base64.encodeBase64String(signature);
}

然后我对此签名的用法如下所示:

String signature = sign(
    /* AWS Secret Access Key copied directly out of the AWS Console */,
    /* policy properly serialized as JSON */);

For some reason, I'm struggling with the signature generation for my Amazon S3 upload policy. I swear I had this working at one point but no longer. Any help would be much appreciated. I need a fresh set of eyes.

When comparing to the output from Amazon S3 Signature Tester, I am not getting the same signature. However, when I directly use the signature coming out of that tool, everything works fine. So the issue is definitely in my signing process. Also, the "String to be signed" hex-decoded coming out of that tool is identical to my input policy being signed.

The AWS docs say the process for constructing a policy signature should go like this:

  1. Encode the policy using UTF-8.
  2. Encode those UTF-8 bytes using Base64.
  3. Sign the policy with your Secret Access Key using HMAC SHA-1.
  4. Encode the SHA-1 signature using Base64.

Seems straight-forward enough. The only place for ambiguity might be in #3. The AWS docs show a sample snippet for generating HMAC-SHA1 and this is consistent with other Java cryptography examples I've seen.

I'm using v1.6 of Apache Commons implementation of Base64. My signing code basically looks like this:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/* ... */

private static final String UTF8 = "UTF-8";
private static final String HMACSHA1 = "HmacSHA1";

public static String sign(String secret, String data) {
    byte[] dataBytes = data.getBytes(UTF8);
    byte[] secretBytes = secret.getBytes(UTF8);

    SecretKeySpec signingKey = new SecretKeySpec(secretBytes, HMACSHA1);

    Mac mac = Mac.getInstance(HMACSHA1);
    mac.init(signingKey);
    byte[] signature = mac.doFinal(dataBytes);

    return Base64.encodeBase64String(signature);
}

And then my usage of this signing looks like:

String signature = sign(
    /* AWS Secret Access Key copied directly out of the AWS Console */,
    /* policy properly serialized as JSON */);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

可是我不能没有你 2025-01-01 06:49:58

好吧,我找到了。显然今天我已经有效地跳过了第二步。我确实将策略 JSON 编码为 Base64,但随后我直接签署 JSON 字符串而不是 Base64 字符串。

第 3 步可能应该改写为“使用 HMAC SHA-1 使用您的秘密访问密钥签署 Base64 策略”。

我想我会保留这个以防其他人遇到类似的问题。

Okay, I found it. Apparently today I've been effectively skipping step #2. I did encode the policy JSON as Base64 but then I am directly signing the JSON string not the Base64 string.

Step #3 should probably be reworded to "Sign the Base64 policy with your Secret Access Key using HMAC SHA-1."

I guess I'll leave this up in case anyone else comes across a similar issue.

做个ˇ局外人 2025-01-01 06:49:58

现在,该程序已得到官方支持。
http://aws.amazon.com/articles/1434

import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

String policy = (new BASE64Encoder()).encode(
policy_document.getBytes("UTF-8")).replaceAll("\n","").replaceAll("\r","");

Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
hmac.doFinal(policy.getBytes("UTF-8")))
.replaceAll("\n", "");

*注意此示例的窗口实现因为有些人从帖子的评论中发现了问题,并且那里还提供了问题的解决方案。

结果可以通过这个来验证
http://s3.amazonaws.com/doc/s3-example -code/post/post_sample.html

然而,有些人说这个“org.apache.commons.codec.binary.Base64”因此更好。
http://www.asgarli.net/2011/03/replacing-sunmiscbase64encoder -and.html

Now, this procedure is officially supported.
http://aws.amazon.com/articles/1434

import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

String policy = (new BASE64Encoder()).encode(
policy_document.getBytes("UTF-8")).replaceAll("\n","").replaceAll("\r","");

Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
hmac.doFinal(policy.getBytes("UTF-8")))
.replaceAll("\n", "");

*Beware the window implementation for this example as some found problem from the comments of the post and solution to the problem was also provided there.

The result can be verified by this
http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html

However, some said this "org.apache.commons.codec.binary.Base64" is better because of this.
http://www.asgarli.net/2011/03/replacing-sunmiscbase64encoder-and.html

乖乖 2025-01-01 06:49:58
String policy_document =
      "{\"expiration\": \"2009-01-01T00:00:00Z\"," +
        "\"conditions\": [" +
          "{\"bucket\": \"s3-bucket\"}," +
          "[\"starts-with\", \"$key\", \"uploads/\"]," +
          "{\"acl\": \"private\"}," +
          "{\"success_action_redirect\": \"http://localhost/\"}," +
          "[\"starts-with\", \"$Content-Type\", \"\"]," +
          "[\"content-length-range\", 0, 1048576]" +
        "]" +
      "}";

    // Calculate policy and signature values from the given policy document and AWS credentials.
    String policy = new String(
        Base64.encodeBase64(policy_document.getBytes("UTF-8")), "ASCII");

    Mac hmac = Mac.getInstance("HmacSHA1");
    hmac.init(new SecretKeySpec(
        aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
    String signature = new String(
        Base64.encodeBase64(hmac.doFinal(policy.getBytes("UTF-8"))), "ASCII");
String policy_document =
      "{\"expiration\": \"2009-01-01T00:00:00Z\"," +
        "\"conditions\": [" +
          "{\"bucket\": \"s3-bucket\"}," +
          "[\"starts-with\", \"$key\", \"uploads/\"]," +
          "{\"acl\": \"private\"}," +
          "{\"success_action_redirect\": \"http://localhost/\"}," +
          "[\"starts-with\", \"$Content-Type\", \"\"]," +
          "[\"content-length-range\", 0, 1048576]" +
        "]" +
      "}";

    // Calculate policy and signature values from the given policy document and AWS credentials.
    String policy = new String(
        Base64.encodeBase64(policy_document.getBytes("UTF-8")), "ASCII");

    Mac hmac = Mac.getInstance("HmacSHA1");
    hmac.init(new SecretKeySpec(
        aws_secret_key.getBytes("UTF-8"), "HmacSHA1"));
    String signature = new String(
        Base64.encodeBase64(hmac.doFinal(policy.getBytes("UTF-8"))), "ASCII");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文