把 AI 交易脚本用的币安 API 密钥从 HMAC 换成 Ed25519

HMAC 还能用,只是文档已经不建议;Ed25519 的私钥在你自己的机器上生成,脚本要改的是签名函数和编码方式。
币安开发者文档的 API Key 类型页现在把 Ed25519 标为推荐类型。HMAC 那一节,中文写的是「不建议使用 HMAC keys。」,英文版用词更重:HMAC keys are deprecated. 两种语言的页面都没写停用日期,请求鉴权页也仍写着支持 HMAC、RSA 和 Ed25519 三种 Key。手上的 HMAC 脚本什么时候换,可以按自己的节奏安排。
换的时候要另建一把 Key。HMAC 的 secret 由交易所生成、和你共享;Ed25519 的密钥对在你自己的机器上生成,交易所那边只存公钥,用它验证你拿私钥签出的请求。脚本里拼参数、带时间戳、放请求头的写法都不用动,要改的是签名那一步:改用私钥计算,结果转成 base64,再做百分比编码,而且大小写敏感。
1. 币安文档为什么改推 Ed25519 而不建议 HMAC #
三种 Key 的差别,在加密方式和签名用的那把密钥握在谁手里:
| Key 类型 | 加密方式 | 签名用的密钥在谁手里 | 优点与短处 |
|---|---|---|---|
| Ed25519(推荐) | 非对称 | 私钥只在你本地;交易所只有公钥 | 安全性与 3072 bits 的 RSA 相当,key 更小、签名更小、签名计算更快 |
| HMAC | 对称 | 交易所生成 secret key 并与你共享,双方用同一串签名和验证 | 签名可以快速计算和压缩;但 secret 要在多方之间共享,不如非对称加密安全 |
| RSA | 非对称 | 私钥只在你本地;支持 2048 和 4096 bits | 比 HMAC 安全,但签名比 HMAC 和 Ed25519 大很多,会降低性能 |
HMAC 的短处落在「共享」上:同一串 secret 存在交易所和你这两头,你这头还可能散在配置文件、服务器环境变量和备份里。非对称 Key 把签名能力只放在私钥上,交易所那边存的公钥只能用来验证。
文档建议换成非对称 Key,举的例子是 Ed25519 或 RSA,两种都在建议范围内。这里选 Ed25519,一是它在所有受支持类型里被推荐,二是部分币安 API(例如 FIX API)要求使用 Ed25519 密钥,RSA 密钥只能用在明确支持 RSA 鉴权的接口上(见非对称密钥生成器页)。
2. 用币安的非对称密钥生成器在本地生成 Ed25519 密钥对 #
这个生成器能产出 Ed25519(PKCS#8)、RSA-2048、RSA-4096 三种密钥对,源代码和版本发布放在 GitHub 的 asymmetric-key-generator 仓库,在币安开发者文档的「SDK 与工具 → 工具」下能找到说明页。使用方式有三种:
- 下载预构建的桌面程序(说明页标为推荐):macOS、Windows、Linux 都能用,从 GitHub Releases 页面下载。
- 从源码构建:克隆仓库后
npm install,再npm run start在本地运行。 - 命令行:装好依赖后用
npm run generate,在没有图形界面的服务器上也能生成。
下载的是预构建程序的话,打开前用随包提供的校验文件核对完整性:
sha256sum -c AsymmetricKeyGenerator-<version>.CHECKSUM
输出显示 OK 才算通过。显示的不是 OK,这个安装包就别打开,删掉后从 Releases 页面重新下载,再核一次。
桌面程序里的操作是这几步:
- 打开程序,密钥类型选 Ed25519(说明页写的是大多数情况下推荐这一种)。
- 点 Generate Key Pair(生成密钥对)。
- 把私钥存到受保护的位置。
- 保存公钥,建 API Key 时要用。
用命令行生成时,-k 指定类型,-p 设密码短语:
npm run generate -- -k ed25519 -p <你的密码短语>
公钥长什么样,可以对照 API Key 类型页给的 Ed25519 key 例子:以 -----BEGIN PUBLIC KEY----- 开头、以 -----END PUBLIC KEY----- 结尾,例子里中间只有一行字符。拿到的文件开头带 PRIVATE KEY 字样的是私钥,别传错。
3. 在 API 管理页新建 Key 时只上传公钥 #
API Key 在币安账户的 API 管理页面创建。Ed25519 这把 Key 建好之后,按这个顺序把脚本切过去:
- 新 Key 的 API Key 字符串照旧放在请求头
X-MBX-APIKEY里,和 HMAC 时一样。 - 在 API 管理里给新 Key 开权限。默认情况下 API Key 不能交易,要下单就得先启用交易权限;只读数据的脚本别开。权限怎么分、开到哪一档,见给 AI 开 Binance API:只开只读权限,提现权限绝不能开。
- 旧 Key 上设过 IP 白名单、想保留同样限制的,新 Key 要重新设一遍。新 Key 第一次请求就报 -2015,按币安 API 报 -2015 是 Key、IP 还是权限没对上里的顺序查。
- 用新 Key 发一个只读的签名请求(比如查账户信息),返回正常、再确认没有别的脚本还在用旧 Key 之后,回到 API 管理撤销那把 HMAC Key。定期轮换密钥、撤销不用的凭证,本来就是生成器说明页列的安全做法之一。
新旧两把 Key 并存的这段时间,两套配置分开放,别让脚本在同一次请求里拿 HMAC 那把的 API Key 去配 Ed25519 的签名。
4. 把脚本里的 HMAC 签名改成 Ed25519 签名 #
签名原文(payload)的拼法不随 Key 类型变:参数写成 参数=取值,用 & 连接,查询字符串和 HTTP body 不加分隔符拼在一起,其中的非 ASCII 字符在签名前要做百分比编码。SIGNED 请求照样要带 timestamp;recvWindow 不发时默认 5000 毫秒,最大 60000 毫秒。时间戳相关的报错和 Key 类型无关,按币安 API 报 -1021 怎么办:时间戳超出 recvWindow 的排查顺序处理。
变的是 payload 拼好之后那一段:
| 环节 | HMAC | Ed25519 |
|---|---|---|
| 拿什么签 | 交易所给的 secretKey | 本地的私钥文件 |
| 签出来的结果 | 示例里是一串 64 位十六进制字符 | 签名结果要编码成 base64 |
| 放进 signature 之前 | 直接使用 | 对 base64 字符串再做百分比编码 |
| 大小写 | 签名不区分大小写(secretKey 和 payload 区分) | payload 和签名都区分大小写 |
用 Python 写的脚本,签名部分前后对比大致是这样,发请求的代码沿用你原来的:
import base64, hashlib, hmac
from cryptography.hazmat.primitives.serialization import load_pem_private_key
# HMAC:旧写法
signature = hmac.new(secret_key.encode(), payload.encode(), hashlib.sha256).hexdigest()
# Ed25519:新写法
with open(PRIVATE_KEY_PATH, 'rb') as f:
private_key = load_pem_private_key(data=f.read(), password=passphrase)
signature = base64.b64encode(private_key.sign(payload.encode('ASCII')))
生成私钥时没设密码短语,password 传 None;设了就传密码短语的字节串,密码短语本身从环境变量读,别写死在代码里。
百分比编码这一步要单独留意。base64 结果里会出现 /、+ 和结尾的 =,编码后分别是 %2F、%2B、%3D,比如示例签名开头的 HaZnek7KOGa/k5+f6Q,放进请求时是 HaZnek7KOGa%2Fk5%2Bf6Q。自己拼 URL 字符串的,要对签名做一次编码(Python 可以用 urllib.parse.quote(signature, safe=''));把签名放进参数字典、交给 requests 的 data= 发送的,由库去编码,别再手动编码一次。
还有一处要删:脚本里如果有把签名统一转成大写或小写的处理,HMAC 下不影响验证,Ed25519 签名大小写敏感,这一行留着就会出错。让 AI 改脚本时,把上面这张表和代码对比一起给它,要求只动签名函数,改完列出改了哪几行,你逐行核对。
5. 还在用 HMAC Key 的脚本该怎么安排迁移 #
币安 API 的 HMAC Key 现在还能用吗?
请求鉴权页仍把 HMAC 列为支持的 Key 类型之一。API Key 类型页的中文版写的是不建议使用,英文版写 deprecated,建议换成 Ed25519 或 RSA 这类非对称 Key,页面上没有给出停用日期。
币安 API 选 RSA 还是 Ed25519?
两种都是非对称 Key,都比 HMAC 安全。RSA 签名比 HMAC 和 Ed25519 大很多,会降低性能;Ed25519 的安全性与 3072 bits 的 RSA 相当,签名更小、计算更快。FIX API 这类接口要求 Ed25519,没有特殊需要就选 Ed25519。
生成 Ed25519 密钥对时一定要设密码短语吗?
密码短语可设可不设,生成器说明页建议在支持的情况下使用;文档的 Python 签名示例用的是没加密的私钥,注释里同时建议用强密码。设了密码短语,脚本加载私钥时要把它传进去。
换成 Ed25519 后 timestamp 和 recvWindow 要改吗?
时间戳和 recvWindow 的规则对三种 Key 一样,换 Key 不用动。SIGNED 请求照样带当前时间戳,单位是毫秒或微秒;recvWindow 不发时默认 5000 毫秒,最大 60000 毫秒,文档不推荐设到 5 秒以上。
— PromptDeck, 2026-11-05