【问题标题】:InvalidSignatureException Sending POST request to AWS Kinesis from SQLInvalidSignatureException 从 SQL 向 AWS Kinesis 发送 POST 请求
【发布时间】:2021-12-13 11:47:17
【问题描述】:

我正在尝试将数据从 SQL 发送到我的 kinesis 流,但我只能恢复错误。

{
    "__type": "InvalidSignatureException",
    "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."
}

我的密钥和秘密是正确的,因为我在 Postman 中进行了成功的测试。

这是我创建身份验证标头的函数...

ALTER FUNCTION [dbo].[CreateAuth]
(
    @awsAccessKey NVARCHAR(MAX),
    @awsSecretKey NVARCHAR(MAX),
    @content NVARCHAR(MAX),
    @dateTime Datetime
)
RETURNS VARCHAR(MAX)
AS
BEGIN

    DECLARE @awsRegion NVARCHAR(MAX) = 'eu-west-2';
    DECLARE @awsService NVARCHAR(MAX) = 'kinesis';
    DECLARE @timeStamp NVARCHAR(16) = FORMAT(@dateTime, 'yyyyMMddTHHmmssZ');
    DECLARE @scope NVARCHAR(MAX) = FORMAT(@dateTime, 'yyyyMMdd') + '/'+@awsRegion+'/'+@awsService+'/aws4_request'

    DECLARE @x_amz_content_sha256 NVARCHAR(MAX);
    DECLARE @hexbin VARBINARY(max) =  HASHBYTES('SHA2_256 ',@content);   

    SET @x_amz_content_sha256 = LOWER(CONVERT([varchar](512), @hexbin,2))
    
    -- CANONICAL REQUEST
        DECLARE @CanonicalRequest NVARCHAR(MAX) = '';
        -- HTTP verb
        SET @CanonicalRequest += 'POST' + CHAR(13) 
        -- URL
        SET @CanonicalRequest += 'kinesis.eu-west-2.amazonaws.com' + CHAR(13) 

        -- QUERYSTRING (must be sorted alphbetically)
        SET @CanonicalRequest += '' + CHAR(13) 

        -- HEADERS (must be sorted alphbetically)
        SET @CanonicalRequest += 'content-type:application/x-amz-json-1.1' + CHAR(13) 
        SET @CanonicalRequest += 'host:kinesis.eu-west-2.amazonaws.com' + CHAR(13) 
        SET @CanonicalRequest += 'x-amz-content-sha256:' + @x_amz_content_sha256 + CHAR(13) 
        SET @CanonicalRequest += 'x-amz-date:' + @timeStamp + CHAR(13) 
        SET @CanonicalRequest += 'x-amz-target:' + 'Kinesis_20131202.PutRecord' + CHAR(13) 

        -- SIGNED HEADERS
        DECLARE @signedheaders NVARCHAR(MAX) = 'content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target'
        SET @CanonicalRequest += @signedheaders + CHAR(13) 

        -- HASHED PAYLOAD
        SET @CanonicalRequest += @x_amz_content_sha256

        DECLARE @CanonicalRequestHexbin VARBINARY(max) = HASHBYTES('SHA2_256 ',@CanonicalRequest);  

    -- STRING TO SIGN
        DECLARE @stringToSign NVARCHAR(MAX) = '';
        SET @stringToSign += 'AWS4-HMAC-SHA256' + CHAR(13) 
        SET @stringToSign += @timeStamp + CHAR(13) 
        SET @stringToSign += @scope + CHAR(13) 
        SET @stringToSign += LOWER(CONVERT([varchar](512), @CanonicalRequestHexbin,2))

    -- CALCULATE SIGNATURE
        DECLARE @DateKey VARBINARY(64); 
        DECLARE @DateRegionKey VARBINARY(64);
        DECLARE @DateRegionServiceKey VARBINARY(64);
        DECLARE @SigningKey VARBINARY(64);
        DECLARE @Signature VARBINARY(64);

        SET @DateKey                = dbo.HMAC('SHA2_256',CONVERT(VARBINARY(MAX), 'AWS4'+@awsSecretKey),CONVERT(VARBINARY(MAX),FORMAT(@dateTime, 'yyyyMMdd')))
        SET @DateRegionKey          = dbo.HMAC('SHA2_256', @DateKey,                CONVERT(VARBINARY(MAX),@awsRegion))
        SET @DateRegionServiceKey   = dbo.HMAC('SHA2_256', @DateRegionKey,          CONVERT(VARBINARY(MAX),@awsService))
        SET @SigningKey             = dbo.HMAC('SHA2_256', @DateRegionServiceKey,   CONVERT(VARBINARY(MAX),'aws4_request'))

        SET @Signature = dbo.HMAC('SHA2_256',@SigningKey,CONVERT(VARBINARY(MAX),@stringToSign));

    --BUILD Authorization
    DECLARE @AuthValue NVARCHAR(MAX) = '';
    SET @AuthValue += 'AWS4-HMAC-SHA256 Credential=' + @awsAccessKey + '/'+ @scope 
    SET @AuthValue += ',SignedHeaders=' + @signedheaders 
    SET @AuthValue += ',Signature=' + LOWER(CONVERT([varchar](512), @Signature,2))

    RETURN @AuthValue

这是对 kinesis 的调用

-- Open the connection.
    EXEC @ret = sp_OACreate 'MSXML2.ServerXMLHTTP', @token OUT;
    IF @ret <> 0 RAISERROR('Unable to open HTTP connection.', 10, 1);

-- Send the request.
    EXEC @ret = sp_OAMethod @token, 'open', NULL, 'POST', @url, 'false';
    SET @auth = dbo.CreateAuth('MYACCESSKEY','MYSECRETKEY',@postData, @datetime)
    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Authorization', @auth

    PRINT @auth
    PRINT ''

    DECLARE @hexbin VARBINARY(max) =  HASHBYTES('SHA2_256 ',@postData); --hash data
    DECLARE @x_amz_content_sha256 NVARCHAR(MAX) = LOWER(CONVERT([varchar](512), @hexbin,2)) -- get hex of hashed data
    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'content-type', @contentType;
    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'host', 'kinesis.eu-west-2.amazonaws.com';
    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'x-amz-content-sha256', @x_amz_content_sha256;
    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'x-amz-date', @xAmzDate;
    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'x-amz-target', @xAmzTarget;
    EXEC @ret = sp_OAMethod @token, 'send', NULL, @postData;

-- Handle the response.
    EXEC @ret = sp_OAGetProperty @token, 'status', @status OUT;
    EXEC @ret = sp_OAGetProperty @token, 'statusText', @statusText OUT;
    EXEC @ret = sp_OAGetProperty @token, 'responseText', @responseText OUT;

-- Show the response.
    PRINT 'Status: ' + @status + ' (' + @statusText + ')';
    PRINT 'Response text: ' + @responseText;

-- Close the connection.
    EXEC @ret = sp_OADestroy @token;
    IF @ret <> 0 RAISERROR('Unable to close HTTP connection.', 10, 1);

我使用的 HMAC 函数就是这个...https://gist.github.com/rmalayter/3130462 我已经使用https://codebeautify.org/验证了使用 SHA2_256 和 HMAC 函数产生的结果是正确的

我很确定我所做的一切都是根据...https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.htmlhttps://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html

我不知道下一步该做什么。

【问题讨论】:

  • 我会记录整个发布请求(假设您使用的库可以这样做)并将其与您通过 Postman 成功发送的请求进行比较。
  • dbo.CreateAuth 函数有许多硬编码值,这些值可能与调用代码使用的变量不同,例如:content-typehostx-amz-target。为什么这些值不作为参数传递给函数?
  • 另外,dbo.CreateAuth 函数似乎没有使用正确的CanonicalURI 值。根据Signature Calculations for the Authorization Header: Transferring Payload in a Single Chunk (AWS Signature Version 4) 页面,它应该是主机名之后的绝对URI 部分,直到? 分隔查询字符串。 UDF 中的代码仅使用硬编码的主机名kinesis.eu-west-2.amazonaws.com
  • 感谢 cmets。我已按照建议删除了硬编码。
  • CanonicalRequest 现在看起来像 ` POST / content-type:application/x-amz-json-1.1 host:kinesis.eu-west-2.amazonaws.com x-amz-content-sha256:3d2457d22cb5bb26de14e45c97e2a22d49b68887cf6f1a2b2757f9d9a6 X-AMZ-DATE:20211214T094829Z X-AMZ-target:Kinesis_20131202.putRecord内容类型;主机; X-AMZ-Content-SHA256; X-AMZ-TATER-SHA256; X-AMZ-Target 3D2457D22CB5BB26DE14E45C97E2A22D49B6887CF6F1A2B2757F9D9A6A8E6C4`和我的StringTosign看起来像“AWS4 -HMAC-SHA256 20211214T094829Z 20211214/eu-west-2/kinesis/aws4_request 51debfe0372257843589cef3c6bcd278b4ffe695360063729848991474b3b29a`

标签: sql-server amazon-web-services amazon-kinesis


【解决方案1】:

我现在已经解决了。除了我懒惰的硬编码之外,还有很多问题。

  • CanonicalURI 应该只是“/”。 - 感谢@AlwayLearning。
  • 已将所有字符串变量更改为 VARCHAR 而不是 NVARCHAR,这会导致哈希不正确。
  • @datekey 使用的日期也需要是 VARCHAR CONVERT(VARCHAR(MAX),FORMAT(@dateTime, 'yyyyMMdd')),因为 FORMAT() 函数返回 NVARCHAR。

我发现这个网站很有帮助http://aws-signature.com.s3-website-us-west-2.amazonaws.com/

成功的函数现在看起来像这样......

ALTER FUNCTION [dbo].[CreateAuth]
(
    @awsAccessKey VARCHAR(MAX),
    @awsSecretKey VARCHAR(MAX),
    @content VARCHAR(MAX),
    @dateTime Datetime,
    @awsRegion VARCHAR(MAX),
    @awsService VARCHAR(MAX),
    @CanonicalRequestURI VARCHAR(MAX),
    @host VARCHAR(MAX),
    @xAmzTarget VARCHAR(MAX),
    @contentType VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
    DECLARE @date VARCHAR(8) = FORMAT(@dateTime, 'yyyyMMdd')
    DECLARE @timeStamp VARCHAR(16) = FORMAT(@dateTime, 'yyyyMMddTHHmmssZ');
    DECLARE @scope VARCHAR(MAX) = @date + '/'+@awsRegion+'/'+@awsService+'/aws4_request'

    DECLARE @x_amz_content_sha256 VARCHAR(MAX);
    DECLARE @hexbin VARBINARY(max) =  HASHBYTES('SHA2_256 ',@content);   

    SET @x_amz_content_sha256 = LOWER(CONVERT([varchar](MAX), @hexbin,2))
    
    -- CANONICAL REQUEST
        DECLARE @CanonicalRequest VARCHAR(MAX) = '';
        -- HTTP verb
        SET @CanonicalRequest += 'POST' + CHAR(10) 
        -- URL
        SET @CanonicalRequest += @CanonicalRequestURI + CHAR(10) 

        -- QUERYSTRING (must be sorted alphbetically)
        SET @CanonicalRequest += '' + CHAR(10) 

        -- HEADERS (must be sorted alphbetically)
        SET @CanonicalRequest += 'content-type:' + @contentType + CHAR(10) 
        SET @CanonicalRequest += 'host:' + @host + CHAR(10) 
        SET @CanonicalRequest += 'x-amz-content-sha256:' + @x_amz_content_sha256 + CHAR(10) 
        SET @CanonicalRequest += 'x-amz-date:' + @timeStamp + CHAR(10) 
        SET @CanonicalRequest += 'x-amz-target:' + @xAmzTarget + CHAR(10) 
        SET @CanonicalRequest +=  CHAR(10)  

        -- SIGNED HEADERS
        DECLARE @signedheaders VARCHAR(MAX) = 'content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target'
        SET @CanonicalRequest += @signedheaders + CHAR(10) 

        -- HASHED PAYLOAD
        SET @CanonicalRequest += @x_amz_content_sha256

        DECLARE @CanonicalRequestHexbin VARBINARY(max) = HASHBYTES('SHA2_256 ',@CanonicalRequest);  

    -- STRING TO SIGN
        DECLARE @stringToSign VARCHAR(MAX) = '';
        SET @stringToSign += 'AWS4-HMAC-SHA256' + CHAR(10) 
        SET @stringToSign += @timeStamp + CHAR(10) 
        SET @stringToSign += @scope + CHAR(10) 
        SET @stringToSign += LOWER(CONVERT([varchar](MAX), @CanonicalRequestHexbin,2))

    -- CALCULATE SIGNATURE
        DECLARE @DateKey VARBINARY(MAX); 
        DECLARE @DateRegionKey VARBINARY(MAX);
        DECLARE @DateRegionServiceKey VARBINARY(MAX);
        DECLARE @SigningKey VARBINARY(MAX);
        DECLARE @Signature VARBINARY(MAX);

        SET @DateKey                = dbo.HMAC('SHA2_256',CONVERT(VARBINARY(MAX), 'AWS4'+@awsSecretKey),CONVERT(VARBINARY(MAX),@date))
        SET @DateRegionKey          = dbo.HMAC('SHA2_256', @DateKey,                CONVERT(VARBINARY(MAX),@awsRegion))
        SET @DateRegionServiceKey   = dbo.HMAC('SHA2_256', @DateRegionKey,          CONVERT(VARBINARY(MAX),@awsService))
        SET @SigningKey             = dbo.HMAC('SHA2_256', @DateRegionServiceKey,   CONVERT(VARBINARY(MAX),'aws4_request'))

        SET @Signature = dbo.HMAC('SHA2_256',@SigningKey,CONVERT(VARBINARY(MAX),@stringToSign));

    --BUILD Authorization
    DECLARE @AuthValue VARCHAR(MAX) = '';
    SET @AuthValue += 'AWS4-HMAC-SHA256 Credential=' + @awsAccessKey + '/'+ @scope 
    SET @AuthValue += ',SignedHeaders=' + @signedheaders 
    SET @AuthValue += ',Signature=' + LOWER(CONVERT([varchar](MAX), @Signature,2))

    RETURN @AuthValue
    
END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-20
    • 2020-12-05
    • 2021-05-29
    • 2014-08-04
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多