You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Go语言实现HMACSHA256与Binance API预期签名不符问题

问题分析与解决方案

你遇到的核心问题有两个,其中第一个直接导致签名结果和命令行输出不一致:

1. 输出编码格式不匹配

openssl dgst -sha256 -hmac默认输出的是十六进制(hex)字符串,但你的Go代码里用了base64.StdEncoding.EncodeToString把HMAC结果转成了Base64编码——这两种编码格式完全不同,自然结果天差地别。

2. 参数转义的潜在隐患(当前示例巧合匹配,但真实请求会出问题)

你待签名的参数里用的是&(HTML转义后的&符号),而Binance API要求的签名参数是用原始的&分隔键值对。你当前命令行用&能得到文档示例结果,是因为文档里的示例参数是HTML转义后的展示形式,但真实调用API时,你必须用未转义的&,否则签名会验证失败。


修正后的Go代码

下面是调整后的代码,既解决了编码问题,也处理了参数转义的潜在风险:

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"fmt"
	"html"
)

func main() {
	docSecret := "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
	// 示例中保留了转义的&,真实请求请直接使用&分隔参数
	docQuery := "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1499827319559"
	
	// 将转义的&还原为原始&(真实场景必须做这一步,否则签名验证失败)
	unescapedQuery := html.UnescapeString(docQuery)
	result := hmacify(unescapedQuery, docSecret)
	fmt.Println(result)
}

func hmacify(message string, secret string) string {
	key := []byte(secret)
	h := hmac.New(sha256.New, key)
	h.Write([]byte(message))
	// 把HMAC结果转换为十六进制字符串,与openssl输出格式保持一致
	return fmt.Sprintf("%x", h.Sum(nil))
}

运行这段代码,你会得到和命令行完全一致的结果:c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71


额外注意事项

  • 处理真实HTTP请求时,务必确保待签名参数是原始键值对字符串(用&分隔,无HTML转义),否则Binance服务器会拒绝请求。
  • 真实项目中绝对不要硬编码密钥(示例中为演示方便这么做),建议通过环境变量或安全配置工具管理敏感信息。

内容的提问来源于stack exchange,提问作者K. Rhoda

火山引擎 最新活动