Safe Haven 评分防刷机制,设备 token 加 IP 限频双重保护
评分数据从哪来
Safe Haven 索引里每个应用有两个评分相关字段:
ratingSum:所有提交的评分整数相加的总和ratingCount:提交过评分的唯一设备数
客户端拿到这两个值就能算出平均评分:ratingSum / ratingCount。这两个值是服务端聚合的——每个应用的所有评分提交都被归并到这两个数字里,原始评分记录不对外公开。
防刷的三层设计
Safe Haven 对评分提交做了三层保护:
第一层:设备 token + 包名哈希
客户端提交评分时,会生成一个设备唯一 token(首次提交时生成并存本地),然后把 token 和目标应用的包名做哈希:
uniqueId = SHA256(device_token + packageName)
服务端存这个 uniqueId,而不是原始设备 token 或 IP。这样:
- 每台设备对每个应用只能评一次——
uniqueId相同就认为是同一个设备重复提交,服务端忽略 - 设备 token 不暴露给服务端(只有哈希)
- 即使服务端被拖库,也无法反推出原始设备标识
这一层防住的是:同一台手机反复提交评分、改设备信息作弊。
第二层:IP 限频
服务端对每 IP 地址有每小时 10 次评分提交的硬性限制。超过就拒绝。
同样,服务端存的是IP 的哈希,不是原始 IP 地址。这样:
- 同一根网线后面的 10 台设备每小时总共只能提交 10 次评分
- 服务端不存储原始 IP(隐私设计)
- IP 哈希在限频窗口过期后会被清除
这一层防住的是:农场 IP、换 IP 刷量。
第三层:不公开原始评分数据
Safe Haven 索引里只有聚合后的 ratingSum 和 ratingCount,没有每条评分的时间、内容、评分者信息。这意味着:
- 无法反推出具体哪条评分可能是刷的
- 评分数据不对外开放,爬虫拿不到原始评分行为模式
- 客户端排行榜只看聚合值,刷几条评分对排名的边际影响很小(因为算法有评分数量权重)
评分提交的流程
客户端打开应用详情页 → 用户点评分(1-5 星整数)→
客户端生成 device_token(首次)→
计算 uniqueId = SHA256(device_token + packageName) →
POST 到服务端(带 uniqueId + IP 哈希)→
服务端检查:uniqueId 是否存在 → 存在则忽略(已评过)→
不存在则检查 IP 限频(10次/小时)→ 超限则拒绝 →
通过则 ratingSum += score, ratingCount += 1 →
服务端更新索引 → 下次同步下发新的聚合值
为什么评分数据不对外
Safe Haven 选择只对外公布聚合后的 ratingSum 和 ratingCount,而不是每条评分的详细内容。这个选择有两层考虑:
- 隐私:不记录用户的评分时间、设备 ID 等可识别信息
- 防刷:刷分的人如果看不到原始评分记录,就无法知道"哪条刷了、哪条没刷",难以精准控制刷分节奏
评分是整数 1-5
Safe Haven 的评分只支持整数(1、2、3、4、5),不支持 3.7 这样的小数。聚合后的平均评分可以是小数(4.8、3.5),但每条提交只能是整数。
这个选择让评分更简单——用户不会纠结选 3.5 还是 4.0,服务端存储也只需要整数相加。
和 Google Play 评分的对比
| 维度 | Safe Haven | Google Play |
|---|---|---|
| 防刷 | 设备 token + IP 限频 | 私有黑盒机制 |
| 隐私 | 只存哈希,不存原始设备/IP | 存原始设备标识(用于关联账号) |
| 粒度 | 整数 1-5 | 半星 0.5 增量 |
| 公开数据 | 聚合值(ratingSum + ratingCount) | 聚合值 + 部分评分列表 |