支付宝签名验证

支付宝签名验证

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

官方文档

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

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 是否为该商家本身。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

中亿丰数字科技集团有限公司

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值