Orderhive AWS4 签名备注匹配
Orderhive AWS4 Signature not match
我正在尝试连接到 AWS4 签名方法进行身份验证。
(https://orderhive.docs.apiary.io/#introduction/api-requirements/end-point)
我的 id_token 和 refresh_token 检索 access_key_id、secret_key 和 session_token。
但是当我尝试检索仓库等信息时,每次都会收到:
"message":"The request signature we calculated does not match the
signature you provided. Check your AWS Secret Access Key and signing
method. Consult the service documentation for details.
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20211217T160055Z
20211217/us-east-1/execute-api/aws4_request
8e3dbc663f97508406c4825b74a647765022ae021fa224754701722b7bcf2288'
我正在使用这段代码,就像其他人在我之前在某些示例中所做的那样。
public const string SCHEME = "AWS4";
public const string ALGORITHM = "HMAC-SHA256";
public const string TERMINATOR = "aws4_request";
public const string ISO8601BasicFormat = "yyyyMMddTHHmmssZ";
public const string DateStringFormat = "yyyyMMdd";
public const string X_Amz_Date = "X-Amz-Date";
public const string RegionName = "us-east-1";
public const string ServiceName = "execute-api";
public const string ContentType = "application/json";
public const string SignedHeaders = "content-type;host;id_token;x-amz-date;x-amz-security-token";
public const string X_Amz_Content_SHA256 = "X-Amz-Content-SHA256";
private Account account;
public void GetWarehouse()
{
try
{
WebRequest webRequest = RequestGet("/setup/warehouse", "", "");
using (WebResponse response = webRequest.GetResponse())
{
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string jsonResponse = responseReader.ReadToEnd();
}
}
catch (Exception ex)
{}
}
public WebRequest RequestGet(string canonicalUri, string canonicalQueriString, string jsonString)
{
string hashedRequestPayload = CreateRequestPayload("");
string authorization = Sign(hashedRequestPayload, "GET", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Method = "GET";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("id_token", account.id_token);
webRequest.Headers.Add("X-Amz-Security-Token", account.session_token);
webRequest.Headers.Add(X_Amz_Date, requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add(X_Amz_Content_SHA256, hashedRequestPayload);
return webRequest;
}
private string Sign(string hashedRequestPayload, string requestMethod, string canonicalUri, string canonicalQueryString)
{
var currentDateTime = DateTime.UtcNow;
var accessKey = account.access_key_id;
var secretKey = account.secret_key;
var dateStamp = currentDateTime.ToString(DateStringFormat);
var requestDate = currentDateTime.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
var credentialScope = string.Format("{0}/{1}/{2}/{3}", dateStamp, RegionName, ServiceName, TERMINATOR);
var headers = new SortedDictionary<string, string> {
{ "content-type", ContentType },
{ "host", Host },
{ X_Amz_Date, requestDate.ToString() }
};
string canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
// Task 1: Create a Canonical Request For Signature Version 4
string canonicalRequest = requestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + SignedHeaders + "\n" + hashedRequestPayload;
Console.WriteLine("\nCanonicalRequest:\n{0}", canonicalRequest);
string hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
string stringToSign = SCHEME + "-" + ALGORITHM + "\n" + requestDate + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
Console.WriteLine("\nStringToSign:\n{0}", stringToSign);
// Task 3: Calculate the AWS Signature Version 4
byte[] signingKey = GetSignatureKey(secretKey, dateStamp, RegionName, ServiceName);
string signature = HexEncode(HmacSHA256(stringToSign, signingKey));
Console.WriteLine("\nSignature:\n{0}", signature);
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
string authorization = string.Format("{0} Credential={1}/{2}/{3}/{4}/{5}, SignedHeaders={6}, Signature={7}", SCHEME + "-" + ALGORITHM, accessKey, dateStamp, RegionName, ServiceName, TERMINATOR, SignedHeaders, signature);
Console.WriteLine("\nAuthorization:\n{0}", authorization);
return authorization;
}
private byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256(TERMINATOR, kService);
return kSigning;
}
static byte[] HmacSHA256(String data, byte[] key)
{
string algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static byte[] Hash(byte[] bytes)
{
return SHA256.Create().ComputeHash(bytes);
}
private static string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
有人知道我做错了什么吗?
谢谢!
最后,我改变了我的 Sign 方法:
public async Task<HttpRequestMessage> Sign(HttpRequestMessage request, string service, string region, TimeSpan? timeOffset = null)
{
if (!IsValidRequest(request, service, region))
throw new Exception("Invalid request!");
if (request.Headers.Host == null)
{
request.Headers.Host = request.RequestUri.Host;
}
var payloadHash = await GetPayloadHash(request.Content);
if (request.Headers.Contains("x-amz-content-sha256") == false)
request.Headers.Add("x-amz-content-sha256", payloadHash);
if (request.Headers.Contains("x-amz-security-token") == false)
request.Headers.Add("x-amz-security-token", Account.session_token);
var t = DateTimeOffset.UtcNow;
if (timeOffset.HasValue)
t = t.Add(timeOffset.Value);
var amzDate = t.ToString(ISO8601BasicFormat);
var dateStamp = t.ToString(DateStringFormat);
request.Headers.Add("x-amz-date", amzDate);
var canonicalUri = string.Join("/", request.RequestUri.AbsolutePath.Split('/').Select(Uri.EscapeDataString));
var canonicalQueryParams = GetCanonicalQueryParams(request);
var signedHeadersList = new List<string>();
var canonicalHeaders = new StringBuilder();
foreach (var header in request.Headers.OrderBy(a => a.Key.ToLowerInvariant(), StringComparer.OrdinalIgnoreCase))
{
var headerValue = (header.Key == "Host") ? EndPoint : string.Join(",", header.Value.Select(s => s.Trim()));
canonicalHeaders.Append($"{header.Key.ToLowerInvariant()}:{headerValue}\n");
signedHeadersList.Add(header.Key.ToLowerInvariant());
}
var signedHeaders = string.Join(";", signedHeadersList);
string canonicalRequest = $"{request.Method}\n{canonicalUri}\n{canonicalQueryParams}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}";
string hashedCanonicalRequest = Hash(Encoding.UTF8.GetBytes(canonicalRequest.ToString()));
var credentialScope = $"{dateStamp }/{region}/{service}/{Terminator}";
var signingKey = GetSignatureKey(Account.secret_key, dateStamp, region, service);
var stringToSign = $"{AWS4AlgorithmTag}\n{amzDate}\n{credentialScope}\n{hashedCanonicalRequest}";
var signature = ToHexString(HmacSha256(signingKey, stringToSign));
string authorization = $"{AWS4AlgorithmTag} Credential={Account.access_key_id}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}";
request.Headers.TryAddWithoutValidation("Authorization", authorization);
return request;
}
现在一切正常。非常重要的一点是:在测试中,Host 需要是好的,https://api.orderhive.com/。我上一个问题的问题是,当我构建 header 时,不知为何,他在 AWS 计算签名时出错了。希望这对遇到此问题的其他人有所帮助。
我正在尝试连接到 AWS4 签名方法进行身份验证。 (https://orderhive.docs.apiary.io/#introduction/api-requirements/end-point)
我的 id_token 和 refresh_token 检索 access_key_id、secret_key 和 session_token。 但是当我尝试检索仓库等信息时,每次都会收到:
"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The String-to-Sign should have been
'AWS4-HMAC-SHA256 20211217T160055Z 20211217/us-east-1/execute-api/aws4_request 8e3dbc663f97508406c4825b74a647765022ae021fa224754701722b7bcf2288'
我正在使用这段代码,就像其他人在我之前在某些示例中所做的那样。
public const string SCHEME = "AWS4";
public const string ALGORITHM = "HMAC-SHA256";
public const string TERMINATOR = "aws4_request";
public const string ISO8601BasicFormat = "yyyyMMddTHHmmssZ";
public const string DateStringFormat = "yyyyMMdd";
public const string X_Amz_Date = "X-Amz-Date";
public const string RegionName = "us-east-1";
public const string ServiceName = "execute-api";
public const string ContentType = "application/json";
public const string SignedHeaders = "content-type;host;id_token;x-amz-date;x-amz-security-token";
public const string X_Amz_Content_SHA256 = "X-Amz-Content-SHA256";
private Account account;
public void GetWarehouse()
{
try
{
WebRequest webRequest = RequestGet("/setup/warehouse", "", "");
using (WebResponse response = webRequest.GetResponse())
{
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string jsonResponse = responseReader.ReadToEnd();
}
}
catch (Exception ex)
{}
}
public WebRequest RequestGet(string canonicalUri, string canonicalQueriString, string jsonString)
{
string hashedRequestPayload = CreateRequestPayload("");
string authorization = Sign(hashedRequestPayload, "GET", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Method = "GET";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("id_token", account.id_token);
webRequest.Headers.Add("X-Amz-Security-Token", account.session_token);
webRequest.Headers.Add(X_Amz_Date, requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add(X_Amz_Content_SHA256, hashedRequestPayload);
return webRequest;
}
private string Sign(string hashedRequestPayload, string requestMethod, string canonicalUri, string canonicalQueryString)
{
var currentDateTime = DateTime.UtcNow;
var accessKey = account.access_key_id;
var secretKey = account.secret_key;
var dateStamp = currentDateTime.ToString(DateStringFormat);
var requestDate = currentDateTime.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture);
var credentialScope = string.Format("{0}/{1}/{2}/{3}", dateStamp, RegionName, ServiceName, TERMINATOR);
var headers = new SortedDictionary<string, string> {
{ "content-type", ContentType },
{ "host", Host },
{ X_Amz_Date, requestDate.ToString() }
};
string canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
// Task 1: Create a Canonical Request For Signature Version 4
string canonicalRequest = requestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + SignedHeaders + "\n" + hashedRequestPayload;
Console.WriteLine("\nCanonicalRequest:\n{0}", canonicalRequest);
string hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
string stringToSign = SCHEME + "-" + ALGORITHM + "\n" + requestDate + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
Console.WriteLine("\nStringToSign:\n{0}", stringToSign);
// Task 3: Calculate the AWS Signature Version 4
byte[] signingKey = GetSignatureKey(secretKey, dateStamp, RegionName, ServiceName);
string signature = HexEncode(HmacSHA256(stringToSign, signingKey));
Console.WriteLine("\nSignature:\n{0}", signature);
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
string authorization = string.Format("{0} Credential={1}/{2}/{3}/{4}/{5}, SignedHeaders={6}, Signature={7}", SCHEME + "-" + ALGORITHM, accessKey, dateStamp, RegionName, ServiceName, TERMINATOR, SignedHeaders, signature);
Console.WriteLine("\nAuthorization:\n{0}", authorization);
return authorization;
}
private byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256(TERMINATOR, kService);
return kSigning;
}
static byte[] HmacSHA256(String data, byte[] key)
{
string algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static byte[] ToBytes(string str)
{
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static byte[] Hash(byte[] bytes)
{
return SHA256.Create().ComputeHash(bytes);
}
private static string HexEncode(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
有人知道我做错了什么吗? 谢谢!
最后,我改变了我的 Sign 方法:
public async Task<HttpRequestMessage> Sign(HttpRequestMessage request, string service, string region, TimeSpan? timeOffset = null)
{
if (!IsValidRequest(request, service, region))
throw new Exception("Invalid request!");
if (request.Headers.Host == null)
{
request.Headers.Host = request.RequestUri.Host;
}
var payloadHash = await GetPayloadHash(request.Content);
if (request.Headers.Contains("x-amz-content-sha256") == false)
request.Headers.Add("x-amz-content-sha256", payloadHash);
if (request.Headers.Contains("x-amz-security-token") == false)
request.Headers.Add("x-amz-security-token", Account.session_token);
var t = DateTimeOffset.UtcNow;
if (timeOffset.HasValue)
t = t.Add(timeOffset.Value);
var amzDate = t.ToString(ISO8601BasicFormat);
var dateStamp = t.ToString(DateStringFormat);
request.Headers.Add("x-amz-date", amzDate);
var canonicalUri = string.Join("/", request.RequestUri.AbsolutePath.Split('/').Select(Uri.EscapeDataString));
var canonicalQueryParams = GetCanonicalQueryParams(request);
var signedHeadersList = new List<string>();
var canonicalHeaders = new StringBuilder();
foreach (var header in request.Headers.OrderBy(a => a.Key.ToLowerInvariant(), StringComparer.OrdinalIgnoreCase))
{
var headerValue = (header.Key == "Host") ? EndPoint : string.Join(",", header.Value.Select(s => s.Trim()));
canonicalHeaders.Append($"{header.Key.ToLowerInvariant()}:{headerValue}\n");
signedHeadersList.Add(header.Key.ToLowerInvariant());
}
var signedHeaders = string.Join(";", signedHeadersList);
string canonicalRequest = $"{request.Method}\n{canonicalUri}\n{canonicalQueryParams}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}";
string hashedCanonicalRequest = Hash(Encoding.UTF8.GetBytes(canonicalRequest.ToString()));
var credentialScope = $"{dateStamp }/{region}/{service}/{Terminator}";
var signingKey = GetSignatureKey(Account.secret_key, dateStamp, region, service);
var stringToSign = $"{AWS4AlgorithmTag}\n{amzDate}\n{credentialScope}\n{hashedCanonicalRequest}";
var signature = ToHexString(HmacSha256(signingKey, stringToSign));
string authorization = $"{AWS4AlgorithmTag} Credential={Account.access_key_id}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}";
request.Headers.TryAddWithoutValidation("Authorization", authorization);
return request;
}
现在一切正常。非常重要的一点是:在测试中,Host 需要是好的,https://api.orderhive.com/。我上一个问题的问题是,当我构建 header 时,不知为何,他在 AWS 计算签名时出错了。希望这对遇到此问题的其他人有所帮助。