支付宝签名验证
支付宝服务器向商家服务器发送消息签名验证
- 在对接支付宝支付时无论何种支付,支付完成后支付宝都会有一个异步的回调通知,此时我们就需要处理其中的消息来更新订单状态。
- 因为接口是对外开放的谁都能请求,所以需要注意接口安全,支付宝给我们发送的消息会带有签名,防止消息被篡改
1. 当我们收到消息是首先就需要对内容进行签名验证
支付宝官方并没有提供Go的sdk
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
}
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)
}
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
}
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 是否为该商家本身。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人