支付宝签名验证

支付宝服务器向商家服务器发送消息签名验证

官方文档

在对接支付宝支付时无论何种支付,支付完成后支付宝都会有一个异步的回调通知,此时我们就需要处理其中的消息来更新订单状态。因为接口是对外开放的谁都能请求,所以需要注意接口安全,支付宝给我们发送的消息会带有签名,防止消息被篡改

1. 当我们收到消息是首先就需要对内容进行签名验证

支付宝官方并没有提供Go的sdk

// CheckSign 校验签名

// @Description: 校验异步通知签名

// @param req_body 请求body a=1&b=2

// @param public_key 支付宝公钥

// @return bool 结果

// @return error

func CheckSign(req_body string, public_key string) (bool, error) {

var sign string

input := map[string]string{}

//解析查询字符串

val, _ := url.ParseQuery(req_body)

for k, v := range val {

if k == "sign" || k == "sign_type" {

if k == "sign" {

sign = v[0]

}

continue

}

//URL解码

value, _ := url.QueryUnescape(v[0])

input[k] = value

}

return checkSign(input, sign, utils.GetPublicKey(public_key))

}

// 自定义排序

type kv struct {

Key string

Value string

}

type SortKv []kv

func (s SortKv) Len() int {

return len(s)

}

func (s SortKv) Less(i, j int) bool {

return s[i].Key < s[j].Key

}

func (s SortKv) Swap(i, j int) {

s[i], s[j] = s[j], s[i]

}

// 处理数据验证签名

func checkSign(input map[string]string, sign string, public_key string) (bool, error) {

var ListKv SortKv

for key, val := range input {

ListKv = append(ListKv, kv{

key, val,

})

}

sort.Sort(ListKv)

var sign_str string

for _, v := range ListKv {

sign_str += v.Key + "=" + v.Value + "&"

}

sign_str = strings.TrimRight(sign_str, "&")

fmt.Println("---------------------------------")

fmt.Println(fmt.Sprintf("签名字符串:%s", sign_str))

fmt.Println(fmt.Sprintf("sign:%s", sign))

fmt.Println(fmt.Sprintf("public_key:%s", public_key))

return utils.Rsa2PubCheckSign(sign_str, sign, public_key, crypto.SHA256)

}

// rsa2公钥签名验证

func Rsa2PubCheckSign(signContent, sign, publicKey string, hash crypto.Hash) (res bool, err error) {

hashed := sha256.Sum256([]byte(signContent))

pubKey, err := ParsePublicKey(publicKey)

if err != nil {

return false, err

}

sig, _ := base64.StdEncoding.DecodeString(sign)

err = rsa.VerifyPKCS1v15(pubKey, hash, hashed[:], sig)

if err != nil {

return false, err

}

return true, nil

}

// 组装公钥

func GetPublicKey(pubkey string) string {

PREFIX := "-----BEGIN PUBLIC KEY-----"

SUFFIX := "-----END PUBLIC KEY-----"

return PREFIX + "\n" + pubkey + "\n" + SUFFIX

}

// ParsePublicKey 解析公钥

func ParsePublicKey(publicKey string) (*rsa.PublicKey, error) {

block, _ := pem.Decode([]byte(publicKey))

if block == nil {

return nil, errors.New("公钥信息错误!")

}

pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)

if err != nil {

return nil, err

}

return pubKey.(*rsa.PublicKey), nil

}

2. 签名可以防止消息被篡改但是不是阻止重放攻击,所以我们还需要验证内容的合法性

以下是官方文档原文

1. 商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。

2. 判断 total_amount 是否确实为该订单的实际金额(即商家订单创建时的金额)。

3. 校验通知中的 seller_id(或者 seller_email ) 是否为 out_trade_no 这笔单据的对应的操作方(有的时候,一个商家可能有多个seller_id/seller_email)。

4. 验证 app_id 是否为该商家本身。

相关文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: