签名及验签指南收藏我的收藏
收藏
我的收藏简介
为了保证「小玩法」的资金和互动数据的安全性,我们提供了一套鉴权认证机制。
当且仅当鉴权认证通过之后,才允许执行相应的接口逻辑。
规则说明
基本规则
- •基本信息
API 请求必须使用 HTTPS。
- •数据格式
Content-Type: application/json Accept: application/json
- •参数兼容性
鉴权认证与请求参数的顺序无关。
- •请求的唯一标示
「开放平台」会给每一个接收到的请求分配一个唯一标示,该标示包含在应答的 HTTP 头
x-tt-logid
中。当需要「开放平台」帮助时,请提供请求的唯一标示,以便我们更快的定位到具体的请求。
http 状态码
状态码 | 错误类型 | 解决方案 |
200 | 处理成功 | / |
400 | 参数错误 | 检查参数是否正确 |
401 | 签名验证失败 | 检查签名方式是否正确 |
500 | 系统签名错误 | 此时响应不带签名,用户可以无视这个响应,当作请求超时来处理。 |
密钥介绍
鉴权认证机制采用
SHA256-RSA2048
实现。使用说明
在鉴权认证机制中,需要 4 个密钥,分别为
- •平台公钥
每个「小程序」对应的平台公钥是不一样的,平台公钥由「开放平台」负责生成,并告知「小程序」开发者。
- •平台私钥
每个「小程序」对应的平台私钥是不一样的,平台私钥由「开放平台」负责生成和保存。
- •应用公钥
「小程序」的应用公钥由开发者生成并上传到「开放平台」,可支持更换。
- •应用私钥(每自然月可更改5次)
「小程序」的应用私钥由开发者生成并保存,不能对外提供,可支持更换。
交互方式如下图所示
应用密钥
- •生成方式
应用公钥和私钥的生成方式可参考
$ openssl OpenSSL> genrsa -out private_key.pem 2048 Generating RSA private key, 2048 bit long modulus ....................+++ ...........................................................................+++ e is 65537 (0x10001) OpenSSL> rsa -in private_key.pem -pubout -out public_key.pem writing RSA key OpenSSL> exit $ ls private_key.pem public_key.pem
注意 ⚠️:应用私钥务必妥善保存,不能对外公开。当发现应用私钥泄漏之后,应及时重新生成,并将新应用公钥上传到「开放平台」。
- •上传方式
- 1.登陆「字节小程序平台」,进入小程序的「开发管理-开发设置」页。
- 2.在「密钥设置」处点击“更新”,将生成的应用公钥上传,上传成功后,鉴权认证机制的前期准备工作就结束了。
平台公钥
平台公钥和私钥由「开放平台」负责生成和保存,不同「小程序」的平台公钥和私钥是不同的。
- •获取方式
- 1.登陆「字节小程序平台」,进入小程序的「开发管理-开发设置」页,平台公钥在「密钥设置」处。
签名介绍
- •签名
「开放平台」通过验证签名来保证请求的真实性和数据的完整性。
- •请求签名
「小程序」首先需要对 URL、消息体等关键数据进行拼接组合,使用应用私钥对组合后的数据进行
SHA256-RSA2048
签名。签名信息通过 HTTP 头Byte-Authorization
传递。「开放平台」会拒绝没有携带签名或者签名验证不通过的请求,并返回
401 Unauthorized
。- •应答签名
「开放平台」会执行 签名验证成功的请求,并使用平台私钥对应答数据进行签名,签名的信息包含在 HTTP 头部。「小程序」应拒绝没有携带签名信息的成功应答(HTTP 状态码为 2xx),应认为是被伪造的或被篡改的应答。
- •回调通知签名
当能力接口涉及回调通知结果时,「开放平台」使用平台私钥对回调通知请求进行签名。签名的方法同应答签名的方法一致,「小程序」务必验证回调通知请求的签名信息。
开发指南
签名生成
「小程序」应按照下述步骤生成请求的签名信息。
- •构造待签名串
待签名串一共有五行,每一行为一个参数。行尾以
\n
(换行符,ASCII 编码值为 0x0A)结束,包括最后一行。如果参数本身以\n
结束,也需要附加一个\n
。最终格式如下HTTP请求方法\n URL\n 请求时间戳\n 请求随机串\n 请求报文主体\n
其中:
- •HTTP 请求方法
如:POST,GET,PUT 等。
- •URL
获取请求的绝对 URL,并去除域名部分得到参与签名的 URL。去除域名后的部分,必须以斜杠字符“/”开头。如果去除域名后的部分为空,则用单个斜杠字符“/”来当作 URL 用于签名。如果请求中有查询参数,URL 末尾应附加有'?'和对应的查询字符串。如:URL 则为/api/business/diamond/query
- •请求时间戳
发起请求时系统的当前时间戳,即格林威治时间 1970 年 01 月 01 日 00 时 00 分 00 秒(北京时间 1970 年 01 月 01 日 08 时 00 分 00 秒)起至现在的总秒数,作为请求时间戳。「开放平台」会拒绝处理一个小时之前发起的请求。命令可参考:date +%s
- •请求随机串
任意生成一个随机字符串,以保证相同时间相同参数发起的请求签名值不一样(我们推荐生成随机串算法如下:调用随机数函数生成,将得到的值转换为字符串)。命令可参考:hexdump -n 16 -e '4/4 "%08X" "\n"' /dev/random
- •请求报文主体
获取请求中的请求报文主体(request body)。
- 1.请求方法为 GET 时,报文主体为空。
- 2.当请求方法为 POST 或 PUT 时,请使用 JSON 报文内容。
- •计算签名值
「小程序」成功构造待签名串后,「小程序」使用应用私钥对待签名串进行
SHA256-RSA2048
签名,并对签名结果进行Base64
编码得到签名值。签名命令可参考
$ echo -n -e \ "POST\n/api/business/diamond/query\n1623934869\nDC10180A100073E70A48F195DA2AF2E6\n{\"appid\":\"ttxxx\",\"order_id\":\"xxx\"}\n" \ | openssl dgst -sha256 -sign private_key.pem | openssl base64 -A nwd1L3wCX+01/TVTkILeovF1DtYeghC1VHjrcjTHVkh7+gRaONEQkC2Y72Mw8JdSnIyeAtyp/pDHzyKGywjVqv5+JOBEhQG1/pvwNHN49wD26qg3AJL4hXw0fMJSRiTQEV1MszwDLuaabvo/qM9OXL9KyYiEPwVJqYtzmho4cHXT6mYgzNOW1xt5d7RDf4QO74JI3i4dtk9Uj8svJTrrBabML6AUcqcx2OP/7xukdaUgPdPf+IqmMG6GC4n52LUDogcL5n/osLdfHg9l6kW5gDcDjBfNDaggz07QMPHGdVao7pnQ2ub7VqcFIuY6Q3cBL7ndQdDGKrv+WBy5Q90QjQ==
- •设置 HTTP Header
签名信息通过 HTTP 头
Byte-Authorization
传递,Byte-Authorization
由认证类型和签名信息两部分组成。Byte-Authorization: 认证类型 签名信息
- •认证类型
目前为SHA256-RSA2048
- •签名信息
- 1.应用
appid
- 2.请求随机串
nonce_str
- 3.请求时间戳
timestamp
- 4.公钥版本
key_version
- 5.签名值
signature
注意 ⚠️:
- 1.以上五项签名信息,无顺序要求
- 2.请求随机串和请求时间戳必须和计算签名值时使用的请求随机串和请求时间戳保持一致
- 3.公钥版本必须填写计算签名值时采用的应用私钥对应的应用公钥版本,应用公钥版本可通过「开发管理-开发设置-密钥设置」处获取
示例如下
Byte-Authorization: SHA256-RSA2048 appid="ttxxx",nonce_str="DC10180A100073E70A48F195DA2AF2E6",timestamp="1623934869",key_version="1",signature="nwd1L3wCX+01/TVTkILeovF1DtYeghC1VHjrcjTHVkh7+gRaONEQkC2Y72Mw8JdSnIyeAtyp/pDHzyKGywjVqv5+JOBEhQG1/pvwNHN49wD26qg3AJL4hXw0fMJSRiTQEV1MszwDLuaabvo/qM9OXL9KyYiEPwVJqYtzmho4cHXT6mYgzNOW1xt5d7RDf4QO74JI3i4dtk9Uj8svJTrrBabML6AUcqcx2OP/7xukdaUgPdPf+IqmMG6GC4n52LUDogcL5n/osLdfHg9l6kW5gDcDjBfNDaggz07QMPHGdVao7pnQ2ub7VqcFIuY6Q3cBL7ndQdDGKrv+WBy5Q90QjQ=="
请求示例如下
curl -v -d '{"appid":"ttxxx","order_id":"xxx"}' -H 'Byte-Authorization : SHA256-RSA2048 appid="ttxxx",nonce_str="DC10180A100073E70A48F195DA2AF2E6",timestamp="1623934869",key_version="1",signature="nwd1L3wCX+01/TVTkILeovF1DtYeghC1VHjrcjTHVkh7+gRaONEQkC2Y72Mw8JdSnIyeAtyp/pDHzyKGywjVqv5+JOBEhQG1/pvwNHN49wD26qg3AJL4hXw0fMJSRiTQEV1MszwDLuaabvo/qM9OXL9KyYiEPwVJqYtzmho4cHXT6mYgzNOW1xt5d7RDf4QO74JI3i4dtk9Uj8svJTrrBabML6AUcqcx2OP/7xukdaUgPdPf+IqmMG6GC4n52LUDogcL5n/osLdfHg9l6kW5gDcDjBfNDaggz07QMPHGdVao7pnQ2ub7VqcFIuY6Q3cBL7ndQdDGKrv+WBy5Q90QjQ=="' -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST https://webcast.bytedance.com /api/business/diamond/query
签名验证
「小程序」应按照下述步骤验证成功应答(HTTP 状态码为 2xx)的签名信息。
- •构造验签名串
应答验签名串一共有三行,每行以
\n
结束,包括最后一行。\n
为换行符(ASCII 编码值为 0x0A)。若应答报文主体为空(如:HTTP 状态码为204 No Content
),最后一行仅为一个\n
换行符。应答时间戳\n 应答随机串\n 应答报文主体\n
- •应答时间戳
从应答 HTTP 头Byte-Timestamp
中获取应答时间戳。
- •应答随机串
从应答 HTTP 头Byte-Nonce-Str
中获取应答随机串。
- •应答报文主体
应答中的应答 JSON 报文主体(response body)。
- •获取应答签名
应答签名值通过 HTTP 头
Byte-Signature
传递。如:Byte-Signature: hWsiaADxS4OKLW/0JpDXiiji+GNRIsnnXsux3nVdyk7X6dqoyyJVYloQR9h/C1DIhGeBKe0i1iciyp6uq4LIkScyQKLhwEaXnWpcYat3+SAgS3ZYcGFY/op/MTO1bf172wbQBamC6gwydOWF0tWlMQb33ZYhztEDnD8iw/JkogOGHjO5uo869xWbgcq0OrkRN4zPGpOc/eiOR/B7fzxbasdMZtENOQMpgPP0z3k/cgeG/DSOwtwfA0eYnpYC8YqvKZ52HI5aCPkexmkfzUqNl1tbVylbMKDQDQoipQSxQPK2fxOFHj+jYu1TQ+nQFeu6amU/1rsMbT8JWa94bwwgkg==
对
Byte-Signature
的签名值使用Base64
解码,得到应答签名。- •校验签名
使用平台公钥对验签名串和应答签名进行
SHA256-RSA2048
签名验证。签名验证命令可参考:
# 1. 把Byte-Signature 的签名值使用Base64解码,并保存到sign.txt文件中 $ openssl base64 -d -A <<< 'hWsiaADxS4OKLW/0JpDXiiji+GNRIsnnXsux3nVdyk7X6dqoyyJVYloQR9h/C1DIhGeBKe0i1iciyp6uq4LIkScyQKLhwEaXnWpcYat3+SAgS3ZYcGFY/op/MTO1bf172wbQBamC6gwydOWF0tWlMQb33ZYhztEDnD8iw/JkogOGHjO5uo869xWbgcq0OrkRN4zPGpOc/eiOR/B7fzxbasdMZtENOQMpgPP0z3k/cgeG/DSOwtwfA0eYnpYC8YqvKZ52HI5aCPkexmkfzUqNl1tbVylbMKDQDQoipQSxQPK2fxOFHj+jYu1TQ+nQFeu6amU/1rsMbT8JWa94bwwgkg==' > sign.txt # 2. 验证签名 $ openssl dgst -sha256 -verify public_key.pem -signature sign.txt << EOF 1623934990 49F0B152663446B14D57DDCA0D5418DB {"order_id":"xxx","order_status":2,"open_id":"openid","pay_tag":"参与游戏"} EOF Verified OK