哔哩哔哩-API收集整理:API签名验证机制深度剖析
在哔哩哔哩(B站)的开放生态中,API(Application Programming Interface,应用程序接口)是连接第三方开发者与平台服务的重要桥梁。随着平台安全需求的提升,API签名验证机制成为保障接口调用合法性和数据安全性的关键环节。本文将深入剖析B站API的签名验证机制,重点讲解WBI签名的工作原理、实现步骤及多语言示例,帮助开发者轻松应对接口调用中的签名难题。
WBI签名机制概述
自2023年3月起,B站Web端部分接口开始采用WBI签名鉴权,表现为在REST API请求的Query参数中添加了w_rid和wts字段。WBI签名鉴权独立于APP鉴权与其他Cookie鉴权,是一种Web端风控手段。
当请求采用WBI签名鉴权的接口时,若签名参数w_rid与时间戳wts缺失或错误,会返回v_voucher,示例如下:
{"code":0,"message":"0","ttl":1,"data":{"v_voucher":"voucher_******"}}
WBI签名机制主要包括获取实时口令、打乱重排生成mixin_key、计算签名w_rid以及添加签名参数四个步骤,下面将详细介绍每个步骤的具体实现。
WBI签名算法详解
1. 获取实时口令img_key和sub_key
img_key和sub_key是WBI签名的核心参数,可通过以下两种方式获取:
- 从nav接口中获取
img_url、sub_url字段的参数。 - 从bili_ticket接口中获取
img、sub字段的参数。
注意:img_url和sub_url看似是图片URL,实则是经过伪装的实时Token,无需访问这些URL。例如:
{"code":-101,"message":"账号未登录","ttl":1,"data":{"isLogin":false,"wbi_img":{"img_url":"https://i0.hdslb.com/bfs/wbi/7cd084941338484aae1ad9425b84077c.png","sub_url":"https://i0.hdslb.com/bfs/wbi/4932caff0ff746eab6f01bf08b70ac45.png"}}}
截取URL中的文件名,即可得到img_key和sub_key,如上述例子中的7cd084941338484aae1ad9425b84077c和4932caff0ff746eab6f01bf08b70ac45。这两个参数全站统一使用,每日更替,建议做好缓存和刷新处理。
2. 生成mixin_key
将sub_key拼接在img_key后面得到raw_wbi_key,然后遍历重排映射表MIXIN_KEY_ENC_TAB,取出raw_wbi_key中对应位置的字符拼接成新字符串,截取前32位即为mixin_key。
重排映射表MIXIN_KEY_ENC_TAB如下:
const MIXIN_KEY_ENC_TAB: [u8; 64] = [
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52
];
例如,img_key为7cd084941338484aae1ad9425b84077c,sub_key为4932caff0ff746eab6f01bf08b70ac45,经过上述操作后得到mixin_key为ea1db124af3c7062474693fa704f4ff8。
3. 计算签名w_rid
首先,在原始请求参数中添加wts字段(当前Unix时间戳,秒级),然后按键名升序排序并进行URL编码,拼接mixin_key后计算MD5值,即为w_rid。
需要注意的是,参数值中的中文或特殊字符编码时字母应大写,空格编码为%20。例如,参数{foo: 'one one four', bar: '五一四', baz: 1919810}应编码为bar=%E4%BA%94%E4%B8%80%E5%9B%9B&baz=1919810&foo=one%20one%20four。
4. 添加签名参数
将计算得到的w_rid和wts追加到原始请求参数的URL Query中,即可完成签名。例如,最终得到bar=514&foo=114&zab=1919810&w_rid=8f6f2b5b3d485fe1886cec6a0be8c5d4&wts=1702204169。
APPKey与签名机制
除了WBI签名,B站API还使用APPKey进行鉴权。APPKey是应用的唯一标识,与APPSEC(密钥)配合使用,用于生成请求签名。以下是部分已知的APPKey及其应用场景:
| APPKEY | APPSEC | platform | APP类型 | 备注 |
|---|---|---|---|---|
| 1d8b6e7d45233436 | 560c52ccd288fed045859ed18bffd973 | android | 粉版 | 获取资源通用 |
| 783bbb7264451d82 | 2653583c8873dea268ab9386918b1d65 | android | 粉版 | 仅获取用户信息时使用(7.X及更新版本) |
| 07da50c9a0bf829f | 25bdede4e1581c836cab73a48790ca6e | android | 概念版 | |
| YvirImLGlLANCLvM | JNlZNgfNGKZEpaDTkCdPQVXntXhuiJEM | ios | - | 视频取流专用 |
详细的APPKey列表可参考APPKey文档。不同的APPKey适用于不同的平台和场景,开发者需根据实际需求选择合适的APPKey。
多语言签名实现示例
Python实现
from functools import reduce
from hashlib import md5
import urllib.parse
import time
import requests
mixinKeyEncTab = [
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52
]
def getMixinKey(orig: str):
return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32]
def encWbi(params: dict, img_key: str, sub_key: str):
mixin_key = getMixinKey(img_key + sub_key)
curr_time = round(time.time())
params['wts'] = curr_time
params = dict(sorted(params.items()))
params = {k: ''.join(filter(lambda chr: chr not in "!'()*", str(v))) for k, v in params.items()}
query = urllib.parse.urlencode(params)
wbi_sign = md5((query + mixin_key).encode()).hexdigest()
params['w_rid'] = wbi_sign
return params
def getWbiKeys() -> tuple[str, str]:
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Referer': 'https://www.bilibili.com/'}
resp = requests.get('https://api.bilibili.com/x/web-interface/nav', headers=headers)
resp.raise_for_status()
json_content = resp.json()
img_url: str = json_content['data']['wbi_img']['img_url']
sub_url: str = json_content['data']['wbi_img']['sub_url']
img_key = img_url.rsplit('/', 1)[1].split('.')[0]
sub_key = sub_url.rsplit('/', 1)[1].split('.')[0]
return img_key, sub_key
img_key, sub_key = getWbiKeys()
signed_params = encWbi({'foo': '114', 'bar': '514', 'baz': 1919810}, img_key, sub_key)
print(urllib.parse.urlencode(signed_params))
JavaScript实现
import md5 from 'md5'
const mixinKeyEncTab = [
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52
]
const getMixinKey = (orig) => mixinKeyEncTab.map(n => orig[n]).join('').slice(0, 32)
function encWbi(params, img_key, sub_key) {
const mixin_key = getMixinKey(img_key + sub_key),
curr_time = Math.round(Date.now() / 1000),
chr_filter = /[!'()*]/g
Object.assign(params, { wts: curr_time })
const query = Object.keys(params)
.sort()
.map(key => {
const value = params[key].toString().replace(chr_filter, '')
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
})
.join('&')
const wbi_sign = md5(query + mixin_key)
return query + '&w_rid=' + wbi_sign
}
async function getWbiKeys() {
const res = await fetch('https://api.bilibili.com/x/web-interface/nav', {
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Referer': 'https://www.bilibili.com/' }
})
const { data: { wbi_img: { img_url, sub_url } } } = await res.json()
return {
img_key: img_url.slice(img_url.lastIndexOf('/') + 1, img_url.lastIndexOf('.')),
sub_key: sub_url.slice(sub_url.lastIndexOf('/') + 1, sub_url.lastIndexOf('.'))
}
}
async function main() {
const { img_key, sub_key } = await getWbiKeys()
const query = encWbi({ foo: '114', bar: '514', baz: 1919810 }, img_key, sub_key)
console.log(query)
}
main()
更多语言的实现示例(如Golang、C#、Java等)可参考WBI签名文档。
总结与注意事项
WBI签名机制是B站Web端API的重要安全措施,开发者在调用相关接口时需严格按照签名步骤生成w_rid和wts参数。同时,应注意以下几点:
img_key和sub_key每日更新,需定期获取并缓存。- 参数排序和编码方式需严格遵循规范,否则会导致签名错误。
- 不同平台和接口可能采用不同的签名机制(如APPKey),需根据实际情况选择合适的鉴权方式。
通过本文的介绍,相信开发者对B站API的签名验证机制有了深入的了解。合理使用API签名机制,不仅能保证接口调用的合法性,还能提升应用的安全性。如需更多API相关信息,可查阅项目中的文档目录。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




