在 C# 中为 AWS REST 查询创建 HMAC 签名
Creating a HMAC signature for AWS REST query in C#
所以我正在尝试对 AWS 的 SNS 服务进行 REST API 调用,但我一直收到 IncompleteSignature 错误。我根据自己 http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/#csharp on how to create the signature and http://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/HMACAuth.html 找出要签名的内容。
这是我想出的测试代码:
static void Main(string[] args)
{
string region = "us-west-2";
string msg = "This is a test!";
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string key = "XXXXXXXXXXXXXXX";
string arn = "arn:aws:sns:us-west-2:xxxxxxxxxx:snstest1";
string query = "Action=Publish&Message=" + HttpUtility.UrlEncode(msg) + "&MessageStructure=json&TargetArn=" + HttpUtility.UrlEncode(arn) + "&SignatureMethod=HmacSHA256&AWSAccessKeyId=" + key + "&SignatureVersion=2&Timestamp=" + HttpUtility.UrlEncode(DateTime.UtcNow.ToString("o"));
string tosign = "GET\nsns." + region + ".amazonaws.com\n/\n" + query;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(tosign);
var hmacsha256 = new HMACSHA256(keyByte);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
query += "&signature=" + HttpUtility.UrlEncode(Convert.ToBase64String(hashmessage));
Console.WriteLine("REST Call: https://sns." + region + ".amazonaws.com/?" + query);
}
知道哪里出了问题吗?
编辑: 我尝试用 http://wiki.alphasoftware.com/~alphafiv/DotNet+Example%3A+Digital+Hash 中的代码更改签名部分,它使用 CharArray 而不是 byte[],不确定哪个是正确的,它产生一个不同的签名,但它仍然不适用于 AWS。
EDIT2: 经过长时间的尝试,我终于发现 AWS 需要 Signature=
而不是 signature=
,但现在我得到了 SignatureDoesNotMatch 错误,所以接下来我需要解决这个问题。我也不知道为什么这种问题会被否决。一旦我弄清楚语法,在任何应用程序中调用 AWS API 都是微不足道的。如果您使用 AWS .NET SDK,您将向二进制文件添加 6 兆字节。这怎么能不值得呢?
解决方案:
此代码有效,无需 AWS SDK 即可发送 SNS 通知:
static void Main(string[] args)
{
string region = "us-west-2";
string msg = "Test test: sfdfds\nfsd: sdsda\n";
string secret = "XXXXXXXXXXXXXXXXXXX";
string key = "ZZZZZZZZZZZ";
string arn = "arn:aws:sns:us-west-2:YYYYYYYYYYY:snstest1";
string query = "AWSAccessKeyId=" + Uri.EscapeDataString(key) + "&Action=Publish&Message=" + Uri.EscapeDataString(msg) + "&SignatureMethod=HmacSHA256&SignatureVersion=2&TargetArn=" + Uri.EscapeDataString(arn) + "&Timestamp=" + Uri.EscapeDataString(System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"));
string tosign = "GET\nsns." + region + ".amazonaws.com\n/\n" + query;
Console.WriteLine(tosign + "\n");
UTF8Encoding encoding = new UTF8Encoding();
HMACSHA256 hmac = new HMACSHA256(encoding.GetBytes(secret));
string signature = Convert.ToBase64String(hmac.ComputeHash(encoding.GetBytes(tosign)));
query += "&Signature=" + Uri.EscapeDataString(signature);
Console.WriteLine("REST Call: https://sns." + region + ".amazonaws.com/?" + query);
}
推出自己的解决方案而不是使用 SDK 并没有错。事实上,我更喜欢它,因为除了更轻量级的代码之外,你更有可能理解意外行为的问题,因为你正在使用本机界面。
这是您所缺少的:
Add the query string parameters ... sorted using lexicographic byte ordering
http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
例如,TargetArn
不应在 SignatureMethod
之前。他们 所有 都需要排序。对于任何给定的消息,只有一个可能的正确签名,因此排序顺序很重要。
所以我正在尝试对 AWS 的 SNS 服务进行 REST API 调用,但我一直收到 IncompleteSignature 错误。我根据自己 http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/#csharp on how to create the signature and http://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/HMACAuth.html 找出要签名的内容。
这是我想出的测试代码:
static void Main(string[] args)
{
string region = "us-west-2";
string msg = "This is a test!";
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string key = "XXXXXXXXXXXXXXX";
string arn = "arn:aws:sns:us-west-2:xxxxxxxxxx:snstest1";
string query = "Action=Publish&Message=" + HttpUtility.UrlEncode(msg) + "&MessageStructure=json&TargetArn=" + HttpUtility.UrlEncode(arn) + "&SignatureMethod=HmacSHA256&AWSAccessKeyId=" + key + "&SignatureVersion=2&Timestamp=" + HttpUtility.UrlEncode(DateTime.UtcNow.ToString("o"));
string tosign = "GET\nsns." + region + ".amazonaws.com\n/\n" + query;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(tosign);
var hmacsha256 = new HMACSHA256(keyByte);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
query += "&signature=" + HttpUtility.UrlEncode(Convert.ToBase64String(hashmessage));
Console.WriteLine("REST Call: https://sns." + region + ".amazonaws.com/?" + query);
}
知道哪里出了问题吗?
编辑: 我尝试用 http://wiki.alphasoftware.com/~alphafiv/DotNet+Example%3A+Digital+Hash 中的代码更改签名部分,它使用 CharArray 而不是 byte[],不确定哪个是正确的,它产生一个不同的签名,但它仍然不适用于 AWS。
EDIT2: 经过长时间的尝试,我终于发现 AWS 需要 Signature=
而不是 signature=
,但现在我得到了 SignatureDoesNotMatch 错误,所以接下来我需要解决这个问题。我也不知道为什么这种问题会被否决。一旦我弄清楚语法,在任何应用程序中调用 AWS API 都是微不足道的。如果您使用 AWS .NET SDK,您将向二进制文件添加 6 兆字节。这怎么能不值得呢?
解决方案:
此代码有效,无需 AWS SDK 即可发送 SNS 通知:
static void Main(string[] args)
{
string region = "us-west-2";
string msg = "Test test: sfdfds\nfsd: sdsda\n";
string secret = "XXXXXXXXXXXXXXXXXXX";
string key = "ZZZZZZZZZZZ";
string arn = "arn:aws:sns:us-west-2:YYYYYYYYYYY:snstest1";
string query = "AWSAccessKeyId=" + Uri.EscapeDataString(key) + "&Action=Publish&Message=" + Uri.EscapeDataString(msg) + "&SignatureMethod=HmacSHA256&SignatureVersion=2&TargetArn=" + Uri.EscapeDataString(arn) + "&Timestamp=" + Uri.EscapeDataString(System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"));
string tosign = "GET\nsns." + region + ".amazonaws.com\n/\n" + query;
Console.WriteLine(tosign + "\n");
UTF8Encoding encoding = new UTF8Encoding();
HMACSHA256 hmac = new HMACSHA256(encoding.GetBytes(secret));
string signature = Convert.ToBase64String(hmac.ComputeHash(encoding.GetBytes(tosign)));
query += "&Signature=" + Uri.EscapeDataString(signature);
Console.WriteLine("REST Call: https://sns." + region + ".amazonaws.com/?" + query);
}
推出自己的解决方案而不是使用 SDK 并没有错。事实上,我更喜欢它,因为除了更轻量级的代码之外,你更有可能理解意外行为的问题,因为你正在使用本机界面。
这是您所缺少的:
Add the query string parameters ... sorted using lexicographic byte ordering
http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
例如,TargetArn
不应在 SignatureMethod
之前。他们 所有 都需要排序。对于任何给定的消息,只有一个可能的正确签名,因此排序顺序很重要。