使用GO进行AWS SNS签名验证

huangapple go评论87阅读模式
英文:

AWS SNS signature verification with GO

问题

我想在GO中实现AWS SNS签名验证。这里是AWS提供的签名验证教程。

然而,有一些我无法理解的地方。

7: 生成Amazon SNS消息的派生哈希值。将Amazon SNS消息以规范格式提交给用于生成签名的相同哈希函数。

如何生成哈希值?我应该使用哪个哈希函数?

8: 生成Amazon SNS消息的断言哈希值。断言哈希值是使用步骤3中的公钥值解密与Amazon SNS消息一起传递的签名的结果。

如何获取断言哈希值

这是我的代码,我有一个通知的结构体

type Notification struct {
    Message          string
    MessageId        string
    Signature        string
    SignatureVersion string
    SigningCertURL   string
    SubscribeURL     string
    Subject          string
    Timestamp        string
    TopicArn         string
    Type             string
    UnsubscribeURL   string
}

我已经生成了规范字符串

signString := fmt.Sprintf(`Message
%v
MessageId
%v`, self.Message, self.MessageId)

if self.Subject != "" {
    signString = signString + fmt.Sprintf(`
Subject
%v`, self.Subject)
}

signString = signString + fmt.Sprintf(`
Timestamp
%v
TopicArn
%v
Type
%v`, self.Timestamp, self.TopicArn, self.Type)

从base64解码签名

signed, err := base64.StdEncoding.DecodeString(self.Signature)

从.pem文件获取证书

resp, _ := http.Get(self.SigningCertURL)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
p, _ := pem.Decode(body)
cert, err := x509.ParseCertificate(p.Bytes)

现在,如何使用我的规范字符串验证签名?以下代码是否正确?

cert.CheckSignature(x509.SHA1WithRSA, signed, []byte(signString))

我总是从上面的代码中得到crypto/rsa: verification error错误。

谢谢!

英文:

I want to implement AWS SNS signature verification in GO. Here is the signature verification tutorial provided by AWS.

However, there are some points I can not get it.

> 7: Generate the derived hash value of the Amazon SNS message. Submit the Amazon SNS message, in canonical format, to the same hash function used to generate the signature.

How to derived the hash value? Which hash function should I use?

> 8: Generate the asserted hash value of the Amazon SNS message. The asserted hash value is the result of using the public key value (from step 3) to decrypt the signature delivered with the Amazon SNS message.

How to get the asserted hash value?

Here is my code, I have a struct for notification:

type Notification struct {
    Message          string
    MessageId        string
    Signature        string
    SignatureVersion string
    SigningCertURL   string
    SubscribeURL     string
    Subject          string
    Timestamp        string
    TopicArn         string
    Type             string
    UnsubscribeURL   string
}

and I've already generated the canonical string:

	signString := fmt.Sprintf(`Message
%v
MessageId
%v`, self.Message, self.MessageId)

	if self.Subject != "" {
		signString = signString + fmt.Sprintf(`
Subject
%v`, self.Subject)
	}

	signString = signString + fmt.Sprintf(`
Timestamp
%v
TopicArn
%v
Type
%v`, self.Timestamp, self.TopicArn, self.Type)

Decode signature from base64

signed, err := base64.StdEncoding.DecodeString(self.Signature)

Get the certificate from .pem

resp, _ := http.Get(self.SigningCertURL)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
p, _ := pem.Decode(body)
cert, err := x509.ParseCertificate(p.Bytes)

Now, how can I verify the signature with my canonical string? Is the following code right?

cert.CheckSignature(x509.SHA1WithRSA, signed, []byte(signString))

I always get crypto/rsa: verification error from above code.

Thanks!

答案1

得分: 4

我知道这是一个很旧的问题,但我遇到了与报告者相同的问题,所以花了一天的时间在AWS的帮助下解决了这个问题。我已经将我的工作作为一个外部库开源,现在可以在这里找到。

你可以像这样使用它(notificationJson是一个JSON字符串):

import (
  "encoding/json"
  "fmt"

  "github.com/robbiet480/go.sns"
)

var notificationPayload sns.Payload
err := json.Unmarshal([]byte(notificationJson), &notificationPayload)
if err != nil {
  fmt.Print(err)
}
verifyErr := notificationPayload.VerifyPayload()
if verifyErr != nil {
  fmt.Print(verifyErr)
}
fmt.Print("Payload is valid!")

感谢lazywei的初步工作,我基于你上面的代码开发了我的库!

英文:

I know this is a really old question, but I had the same problems as the reporter so I took a day to figure this out with the assistance of AWS. I have open sourced my work as an external library, now available here.

You can use it like this (notificationJson is a JSON string):

import (
  "encoding/json"
  "fmt"

  "github.com/robbiet480/go.sns"
)

var notificationPayload sns.Payload
err := json.Unmarshal([]byte(notificationJson), &notificationPayload)
if err != nil {
  fmt.Print(err)
}
verifyErr := notificationPayload.VerifyPayload()
if verifyErr != nil {
  fmt.Print(verifyErr)
}
fmt.Print("Payload is valid!")

Thanks for your initial work on this lazywei, I based my library on your above code!

答案2

得分: 0

在关于Amazon SNS消息签名验证的讨论中,还需要注意到Amazon SNS现在支持基于SHA256哈希的消息签名:

https://aws.amazon.com/about-aws/whats-new/2022/09/amazon-sns-supports-message-signatures-based-sha256-hashing/

这是发布博客文章:

https://aws.amazon.com/blogs/security/sign-amazon-sns-messages-with-sha256-hashing-for-http-subscriptions/

英文:

In the context of this discussion about Amazon SNS message signature verification, it’s also important to notice that Amazon SNS now supports message signatures based on SHA256 hashing:

https://aws.amazon.com/about-aws/whats-new/2022/09/amazon-sns-supports-message-signatures-based-sha256-hashing/

Here's the launch blog post:

https://aws.amazon.com/blogs/security/sign-amazon-sns-messages-with-sha256-hashing-for-http-subscriptions/

huangapple
  • 本文由 发表于 2013年11月16日 13:04:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/20014908.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定