MANKA の Blog
扫码登录百度获取BDUSS

2018-07-17

#百度#百度网盘#百度贴吧

由于各种原因,登录百度获取bduss的方式越来越少了,加上某段时间百度开始限制单一机器用账号密码登录的上限,导致博主的直链解析站所依赖的bduss获取站也挂了,博主一度陷入了烦恼。 百度坑死人

所以博主研究了扫码登录

关于扫码登录

这个功能很早就有了,只是博主一直没去研究,扫码登录能获取有效期长达十年的bduss,但是除了手机百度以外,其他百度系的应用都只能调用摄像头扫码,不能在图库选择图片,这意味着用户必须有两台或以上的设备才能够使用扫码登录。

获取二维码

简单的抓包就可以发现二维码获取的链接

curl "https://passport.baidu.com/v2/api/getqrcode?lp=pc"

然后会返回一串json,反序列化后会得到imgurlsign

{  "imgurl": "passport.baidu.com/v2/api/qrcode?sign=c2db7cc9133219a586606e9468decf3e&lp=pc",  "errno": ,  "sign": "c2db7cc9133219a586606e9468decf3e",  "prompt": "登录后威马将获得百度帐号的公开信息(用户名、头像)"}

剩下那些就不用管了 imgurl就是获取扫码登录用的二维码,而sign是对应二维码的唯一id

不获取二维码直接使用网页授权

二维码只是一个链接,所以可以拼接链接并访问该链接授权

https://wappass.baidu.com/wp/?qrlogin=&sign=c2db7cc9133219a586606e9468decf3e

2020-03-30更新:百度不再允许pc的ua访问此链接,会提示下载手机客户端,移动ua不受影响

获取临时bduss

获得二维码时,经过简单的筛选就可以发现后台在尝试连接一个url,但只要不扫码,一段时间以后会连接超时,然后再次进行请求,周而复始……

curl "https://passport.baidu.com/channel/unicast?channel_id=c2db7cc9133219a586606e9468decf3e&callback="

这里的channel_id其实就是前面获取到的sign,扫了码再获取就不会超时了,不过这里有一个坑,链接里面必须要有callback,即使它没有值…… 然后又有了这货

({"errno":0,"channel_v":"{\"status\":0,\"v\":\"\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\",\"u\":null}"})

双重嵌套json,嗯…… 那个v对应的键值就是临时的bduss

登录

接上面

fetch("https://passport.baidu.com/v3/login/main/qrbdusslogin?bduss=" + JSON.parse(data.channel_v).v)

简单的GET请求,不是么? 然后就可以在返回头那的set-cookie拿你想拿的东西了

心血来潮去看了一下cookie以外返回了些啥

{    "errInfo": {        "no": "0",        "msg": ""    },    "code": "110000",    "message": "",    'data': {        "u": "https:\/\/passport.baidu.com\/",        "userName": "",        "hao123Param": "******FBQUFBQUFBQUFBQU******",        "bdusssign": "",        "authtoken": "",        "session": {            "version": "v3",            "actionType": "",            "canshare": "1",            "authsid": "******",            "needvcode": "0",            "bduss": "******AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA******",            "ptoken": "******",            "stoken": "******",            "ubi": "******",            "stokenList": "[\"tb#******\",\"pp#******\",\"bp#******\",\"netdisk#******\",\"cloudforbusiness#******\",\"bdwm#******\",\"waimai#******\",\"bdwalletsdk#******\",\"baiduwalletapp#******\",\"baidugushitong#******\",\"bdbus#******\",\"fund#******\",\"nuomi#******\",\"licai#******\",\"asset#******\",\"hao123#******\",\"pcs#******\",\"dev#******\",\"fbuym#******\",\"licaiapp#******\",\"mybox#******\",\"iitnightingale#******\",\"dianying#******\",\"mall#******\",\"lv#******\",\"cmovie#******\",\"mapsafe#******\",\"im_hi#******\","ppapp#******\",\"licaient#******\",\"album#******\",\"aduqa#******\"]"        },        "user": {            "username": "******",            "weakpass": "",            "userId": "1",            "livinguname": "",            "portraitUrl": "https:\/\/himg.bdimg.com\/sys\/portrait\/item\/pp.1.******.******.jpg",            "portraitSign": "pp.1.******.******",            "displayName": "******"        }    },    "traceid": ""}

还挺详细的,这不是一个标准的json,使用了单引号 ' 以及加多了一个反斜杠 \, 所以直接使用 JSON.parse()json_decode() 会报错,可以预处理一遍字符串 ("是双引号 ")

str.replace(/'([^'']+)'/gm, `"$1"`)).replace(/\\&/gm, "&")
preg_replace("/'([^'']+)'/", '"$1"', str_replace("\\&", "&", $str))

由于百度每种服务所需要的stoken都不同,这里一次性列出所有stoken stokenList 还是挺方便的

后记

本来很简单的事情研究了一早上,因为curl忘记加上RETURNTRANSFER,被自己蠢哭(逃ε=ε=ε=┏(゜ロ゜;)┛ demo在此,你们要的蓝色的东西https://bduss.nest.moe/

2020-03-30追记:我以前都写了些啥啊


评论区