Amazon S3 POST对象Signature V4签名计算不符问题求助
AWS Signature V4 for S3 POST Upload: Signature Mismatch Issue
我刚帮你排查了这个问题,核心原因是你错误地使用了Base64编码后的policy字符串来计算签名,但AWS要求的是对原始未编码的JSON policy的UTF-8字节进行HMAC-SHA256运算。
问题细节拆解
官方S3 POST上传示例里的expectedBase64Policy只是原始policy JSON的Base64编码结果,用于在表单中传递给S3;但签名计算的源头必须是解码后的原始JSON内容。你当前的代码直接把Base64字符串传给HmacSHA256方法,这就导致最终签名和预期值完全不符。
而你提到通用测试用例能正常匹配,是因为那个测试场景不需要处理Base64编码的输入,所有参数都是直接的明文字符串,所以密钥生成流程完全正确。
修正后的代码示例
只需要在计算签名前,先把Base64编码的policy解码为原始JSON,再用它的UTF-8字节进行签名计算:
public static void test() { try { String expectedBase64Policy = "eyAiZXhwaXJhdGlvbiI6ICIyMDE1LTEyLTMwVDEyOjAwOjAwLjAwMFoiLA0KICAiY29uZGl0aW9ucyI6IFsNCiAgICB7ImJ1Y2tldCI6ICJzaWd2NGV4YW1wbGVidWNrZXQifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAidXNlci91c2VyMS8iXSwNCiAgICB7ImFjbCI6ICJwdWJsaWMtcmVhZCJ9LA0KICAgIHsic3VjY2Vzc19hY3Rpb25fcmVkaXJlY3QiOiAiaHR0cDovL3NpZ3Y0ZXhhbXBsZWJ1Y2tldC5zMy5hbWF6b25hd3MuY29tL3N1Y2Nlc3NmdWxfdXBsb2FkLmh0bWwifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRDb250ZW50LVR5cGUiLCAiaW1hZ2UvIl0sDQogICAgeyJ4LWFtei1tZXRhLXV1aWQiOiAiMTQzNjUxMjM2NTEyNzQifSwNCiAgICB7IngtYW16LXNlcnZlci1zaWRlLWVuY3J5cHRpb24iOiAiQUVTMjU2In0sDQogICAgWyJzdGFydHMtd2l0aCIsICIkeC1hbXotbWV0YS10YWciLCAiIl0sDQoNCiAgICB7IngtYW16LWNyZWRlbnRpYWwiOiAiQUtJQUlPU0ZPRE5ON0VYQU1QTEUvMjAxNTEyMjkvdXMtZWFzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LA0KICAgIHsieC1hbXotYWxnb3JpdGhtIjogIkFXUzQtSE1BQy1TSEEyNTYifSwNCiAgICB7IngtYW16LWRhdGUiOiAiMjAxNTEyMjlUMDAwMDAwWiIgfQ0KICBdDQp9"; String expectedSignature = "46503978d3596de22955b4b18d6dfb1d54e8c5958727d5bdcd02cc1119c60fc9"; String secretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; // 关键修正:解码Base64得到原始policy JSON byte[] decodedPolicyBytes = DatatypeConverter.parseBase64Binary(expectedBase64Policy); String rawPolicy = new String(decodedPolicyBytes, "UTF8"); byte[] signingKey = getSignatureKey(secretKey, "20151229", "us-east-1", "s3", false); // 使用原始policy的UTF-8字节计算签名 byte[] signedPolicy = HmacSHA256(rawPolicy, signingKey); String calculatedSignature = DatatypeConverter.printHexBinary(signedPolicy) .toLowerCase(); System.out.println("Generating signature for policy string for POST object"); System.out.println("EXP: " + expectedSignature); System.out.println("GOT: " + calculatedSignature); // 通用测试用例部分保留不变 System.out.println("Generating signing for test example"); getSignatureKey("wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "20120215", "us-east-1", "iam", true); } catch (Exception e) { e.printStackTrace(); } }
额外检查点
修正后你会发现签名和预期完全匹配,再补充几个后续开发中需要注意的细节:
- 确保所有字符串编码统一使用UTF-8,你的代码里已经正确指定了
"UTF8",这部分没问题 - 确认签名密钥生成时的日期、区域、服务名,必须和policy中
x-amz-date、x-amz-credential字段的对应部分完全一致 - 如果后续自定义policy,要注意JSON格式的正确性(比如引号、逗号不能遗漏),否则即使签名正确,S3也会拒绝请求
内容的提问来源于stack exchange,提问作者ribram
相关产品推荐
相关产品推荐

