这次其实做了一次很典型的浏览器端黑盒逆向 + 故障定位。最后不仅找到了“为什么挂一会就掉登录”,还顺带把华医网课程页的大致运行机制摸清了。
1. 最初的问题
起点只是:
华医网页面挂一会就提示重新登录,到底是 Cookie 到期、Session 超时,还是浏览器后台导致的?
最开始有几种假设:
Cookie 固定过期
SSO token 固定过期
ASP.NET Session idle timeout
播放器心跳停止
Safari / Edge 后台节流
多设备挤掉登录
所以整个过程本质上是在不断缩小假设空间。
2. Cookie 层:先排除了几个伪线索
最先看到:
HWWAFSESID
HWWAFSESTIME
一开始容易把 HWWAFSESTIME 理解成登录时间。
后来确认这其实是华为云 WAF 的安全会话 Cookie:
HWWAFSESID
HWWAFSESTIME
属于 WAF / 防护 / 会话统计体系,不是华医网业务登录凭据。
因此排除:
HWWAFSESTIME ≠ 华医登录过期时间
随后真正值得关注的 Cookie 是:
ASP.NET_SessionId
cookie_user_ticket
sso_code
sso_token
而这些 Cookie 的过期类型全部是:
Session
也就是浏览器侧没有明确:
Expires
Max-Age
所以:
客户端无法直接通过 Cookie 看出服务器什么时候判登录失效。
3. sso_token 被确认是 UUID v4
进一步检查发现:
sso_token
不是 JWT,而是:
xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx
标准 UUID v4 风格。
这意味着它更像:
浏览器持有一个随机 Session ID
↓
服务器根据这个 ID
去 Redis / DB / Session Store 查询登录状态
而不是 JWT:
token 自己包含 iat / exp / user 信息
因此从 sso_token 字符串本身也无法推导 TTL。
这一步把机制进一步缩成了:
客户端:
固定 UUID token
服务器:
保存真正的 session 状态与 TTL
4. LocalStorage 中的“5 秒心跳”其实是神策统计
接着在 LocalStorage 中发现:
sawebjssdkpageleave-...
里面有:
heartbeat_interval_time = 5000
time = 不断变化
一开始很像登录心跳。
后来判断出这是 Sensors Data / 神策分析 PageLeave 插件的数据。
它的职责更接近:
每 5 秒记录页面仍然活着
→ 统计页面停留时间
→ 页面隐藏 / 离开时上报行为分析
而不是:
每 5 秒续华医登录 Session
因此又排除了一个很大的干扰项:
神策 heartbeat ≠ 华医登录 heartbeat
这个过程很典型:看到“heartbeat”不要马上把它理解成业务保活。
5. Network 分析:把流量拆成了两套系统
这是整个逆向里最重要的一步。
观察课程播放时的 Network 后,发现请求大致分成两套。
第一套:POLYV / 保利威视频系统
例如:
prtas.videocc.net/v2/view
以及一些 hash 风格的资源请求:
9fbd5960596d...
实验发现:
播放视频
→ hash 请求不断出现
暂停视频
→ hash 请求停止
所以基本可以确认这些是:
视频分片 / 视频媒体资源
而:
prtas.videocc.net/v2/view
则更像播放器统计、播放日志、流量统计。
因此得出:
视频系统
= POLYV / videocc.net
第二套:华医网自己的业务系统
发现:
https://cme28.91huayi.com/ashx/getCourseWarePlayState.ashx
它返回:
{
"errorCode": "1",
"errMsg": "ok",
"reValue": null,
"reBody": null
}
显然不是视频资源,而是 ASP.NET 业务接口。
从名字判断属于:
获取课件播放状态
它即使视频暂停也会周期发送,所以更像:
课程状态轮询
而不是视频本身。
6. 真正找到核心接口:addCourseWareProcess
之后抓到了最关键的请求:
POST /ashx/addCourseWareProcess.ashx
正常时:
200 OK
响应:
{
"code": 0,
"msg": "ok",
"body": null
}
登录失效后:
401 Unauthorized
响应:
{
"code": 401,
"message": "请重新登录",
"body": null
}
这个接口名字本身已经很明确:
add CourseWare Process
基本就是:
提交 / 保存课件学习进度。
于是整个业务链开始清晰:
POLYV
负责:
视频播放
视频分片
播放器统计
华医网
负责:
登录
课程状态
学习进度
是否完成课程
这也解释了一个非常重要的现象:
华医登录已经失效
↓
POLYV 视频仍然可能继续播放
↓
用户表面上看“课程还在播放”
↓
但 addCourseWareProcess 已经 401
↓
学习进度实际上不再保存
也就是说:
“视频还在播放” ≠ “华医还在正常记学习进度”。
这是整个逆向里最重要的业务发现之一。
7. 401 时 Cookie 仍然存在
接下来又确认了一点:
401 请求发出时:
sso_token
sso_code
ASP.NET_SessionId
...
这些 Cookie 仍然有值并且被正常发送。
因此基本排除:
Safari / Edge 把 Cookie 删除了
Cookie 自己到期消失
真正发生的是:
浏览器:
“这是我的旧 token”
服务器:
“这个 token 我已经不认了”
→ 401
也就是说:
登录失效发生在服务端。
而不是客户端 Cookie 生命周期问题。
8. 一度怀疑固定 SSO TTL
由于:
sso_token
多次成功请求之间值完全不变,所以排除了:
每个请求都刷新成一个新 token
当时剩下两个主要假设:
A. SSO 有绝对过期时间
登录 N 分钟后强制失效
B. 服务端存在 idle timeout
长时间没有有效活动后失效
但真正的突破来自请求时间线。
9. 决定性的时间线异常
正常情况下:
addCourseWareProcess
大约:
每 5 分钟一次。
但某次抓包发现:
14:57
addCourseWareProcess → 200
之后长达约 70 分钟没有请求
16:07
addCourseWareProcess → 401
这时真正异常的地方已经不是:
为什么 16:07 过期?
而是:
为什么一个本应每 5 分钟发生一次的请求,整整 70 分钟没发?
正常情况下应该看到:
14:57
15:02
15:07
15:12
...
16:02
但这些全部消失了。
这一下把重点从:
华医服务端固定 TTL
转移到了:
浏览器后台生命周期
10. 最终定位:Edge 睡眠 / 节能标签页
于是检查 Edge 的:
Sleeping Tabs
Energy Saver
后台标签页冻结
Chromium / Edge 为了节省 CPU、内存和电量,会对长时间后台标签页:
Throttle
→ Freeze
→ Sleep
被冻结后:
setInterval
setTimeout
网页 JS 定时任务
都可能暂停。
于是完整故障链终于成立:
课程正常播放
↓
用户切走 / 页面长期后台
↓
Edge 节能策略将页面冻结 / 睡眠
↓
网页 JS 定时任务停止
↓
addCourseWareProcess 不再每 5 分钟发送
↓
华医服务器长时间没有收到有效业务活动
↓
服务端 Session / SSO 状态失效
↓
页面重新恢复运行
↓
addCourseWareProcess 再次发送
↓
旧 sso_token 仍然被浏览器带上
↓
服务器判定已失效
↓
401 请重新登录
这条链基本把所有观察现象都解释通了。
11. 最终实验验证
你最后做了实际对照:
让网页播放声音
+
把华医网从 Edge 节能 / 睡眠机制中排除
+
Windows 不睡眠
结果:
连续几个小时登录都没有再掉。
而且 addCourseWareProcess 能持续发送。
这相当于给整个假设做了一个很强的实验验证。
因此最终结论可以写成:
华医网本身并没有表现出一个很短的固定登录 TTL。之前的掉登录主要是由于 Edge 在后台对课程页执行节能 / 睡眠策略,导致网页 JS 定时业务请求停止。长时间没有有效业务请求后,服务端 Session/SSO 状态失效。将网站设置为“始终保持活动”并保持媒体播放后,
addCourseWareProcess能持续约每 5 分钟发送,登录状态可以保持数小时。
12. 最后得到的华医网页面模型
现在已经可以画出一个相当清晰的架构:
华医课程页面
│
┌─────────────┴─────────────┐
│ │
▼ ▼
POLYV 保利威 华医业务后端
videocc.net cme28.91huayi.com
│ │
│ ├─ 登录 / SSO
├─ 视频资源 │
├─ 视频分片 ├─ getCourseWarePlayState
├─ 播放日志 │ 课程状态轮询
└─ view统计 │
└─ addCourseWareProcess
学习进度提交
≈ 每 5 分钟
另外还有:
神策 Sensors Data
↓
sawebjssdkpageleave
↓
页面停留 / 用户行为统计
属于第三套统计体系。
所以这个网页至少同时涉及:
华医业务系统
+
POLYV 视频系统
+
神策行为分析系统
+
华为云 WAF
一开始看 Network 很乱,就是因为实际上同时存在四层东西。
13. 这次最值得保留的逆向方法
这次最有价值的不是华医网本身,而是你实际上走完了一套很标准的黑盒 Web 排障流程:
现象
↓
提出多个假设
↓
Cookie / LocalStorage
↓
识别第三方组件
↓
Network 分类
↓
暂停 / 播放做对照实验
↓
区分媒体流量和业务流量
↓
找到核心业务接口
↓
比较成功 / 失败响应
↓
检查客户端凭据是否仍存在
↓
记录请求时间线
↓
发现“应该发生但没有发生”的事件
↓
定位浏览器生命周期
↓
修改单一变量
↓
长时间实验验证
尤其有三个思维点非常值得记住:
第一,关注“缺失的事件”。
真正破案的不是 401,而是:
本该每 5 分钟一次的 addC,为什么 70 分钟完全没出现?
这是比错误本身更强的信号。
第二,不要看到 heartbeat 就认为是保活。
这次有:
神策 5 秒 heartbeat
POLYV 播放统计
华医课程状态轮询
华医学习进度提交
都可以被口语叫作“心跳”,但含义完全不同。
第三,第三方资源正常不代表主业务正常。
视频还在播
只能说明:
POLYV 正常
不能证明:
华医登录正常
学习进度正常
这种“多个子系统独立运行”的问题在真实 Web 系统里非常常见。
这次其实已经不只是“找一个掉登录原因”了,更像是你第一次比较完整地做了一轮基于浏览器 DevTools 的黑盒系统分析:从 Cookie、LocalStorage、HTTP、第三方 SDK、业务接口一直追到浏览器生命周期,最后再用对照实验验证根因。
而这套思路以后无论调 FastAPI 前后端问题、浏览器插件、第三方 API,还是线上系统故障,都能直接复用。
继续完善这次逆向记录
- 画出完整请求时序图
- 整理成一页技术报告