【免费下载链接】lunar-tear
Private server research project for a certain discontinued mobile game
Lunar Tear 是一个针对已停服手游的私服研究项目,由 gRPC 游戏服、HTTP 资源 CDN、auth-server 登录服务和 Admin Webhook 四部分组成。本文带你快速看懂它的完整安全设计:Admin Webhook 如何受 Bearer Token 保护、客户端登录 Token 采用什么签名方案,以及 fail-closed(默认关闭)机制如何保证"未配置就绝不暴露"。
项目架构速览:四服务各司其职
Lunar Tear 的每个服务都只开放必要的端口,管理端点更是被单独隔离:
| 服务 | 二进制 | 端口 | 职责 |
|---|---|---|---|
| 游戏服 | lunar-tear | 8003 | gRPC 主服务,客户端登录、抽卡、任务等 |
| 资源 CDN | octo-cdn | 8080 | 资产包、master data、list.bin 下发 |
| 登录服务 | auth-server | 3000 | 账号注册与登录,签发 Token |
| Admin Webhook | lunar-tear | 8082 | 热重载 master data,默认仅回环 |
服务入口见 server/cmd/lunar-tear/main.go,Admin Webhook 监听地址的默认值就写在命令行参数里——127.0.0.1:8082,只允许本机访问(main.go)。
Admin Webhook:如何安全地"不重启热更新"
私服运营者常需要修改游戏内数据(即 master data 文件assets/release/20240404193219.bin.e)。Lunar Tear 提供一个管理端点POST /api/admin/master-data/reload,让服务器在不重启的情况下重新读取该文件,原子替换全部内存目录,并让在线客户端自动拉取新版数据。
它的实现非常克制,整个逻辑只有几十行,位于 server/cmd/lunar-tear/admin.go。
触发方式:一条带 Bearer Token 的请求
在环境变量中设置LUNAR_ADMIN_TOKEN后,用如下命令即可触发热重载:
curl -X POST -H "Authorization: Bearer ${LUNAR_ADMIN_TOKEN}" \ http://127.0.0.1:8082/api/admin/master-data/reload热重载由 server/internal/runtime/holder.go 中的Holder完成:每次重新加载都会从头构建一份全新的Catalogs快照,再通过原子指针一次性发布,所有 gRPC 请求在开始时调用Get(),因此永远看到一致的数据。
Bearer Token 认证的两层设计
Lunar Tear 中有两类 Bearer Token,分别保护管理面和客户端面。
管理端:LUNAR_ADMIN_TOKEN 与恒定时间比较
Admin Webhook 的鉴权逻辑在 admin.go:
- 只接受
POST,其他方法直接返回405; - 请求头必须是
Authorization: Bearer <token>; - 比较使用
subtle.ConstantTimeCompare(第 36 行),这是防计时侧信道攻击的标准做法——普通字符串比较会在第一个不匹配字节处提前返回,攻击者可据此逐字节猜测 Token,而恒定时间比较消除了这种信息泄露; - 校验失败统一返回
401 unauthorized,不泄露"Token 是空、是格式错还是不匹配"等细节。
客户端:auth-server 签发的 HMAC-SHA256 Token
客户端的"Facebook 登录按钮"实际被重定向到 auth-server,输入用户名/密码后签发一个自定义格式 Token:Base64URL(payload).Base64URL(HMAC-SHA256签名),其中 payload 包含sub(用户 ID)、name、iat(签发时间)、exp(过期时间),有效期固定 24 小时,见 server/internal/auth/token.go。
验证流程在 Validate 函数 中按顺序执行:格式拆分 → Base64 解码 →hmac.Equal恒定时间校验签名 → 解析声明 → 检查过期,任何一步失败都拒绝(ErrTokenInvalid/ErrTokenExpired)。游戏服通过 auth-server 的/me端点换取用户身份,该端点同时兼容access_token查询参数与Authorization: Bearer头两种传法(handlers.go)。
密钥管理也很讲究:--secret省略时,auth-server 启动时用密码学安全随机数生成 32 字节密钥并打印到控制台,提示你在下次重启时通过--secret复用,保证已有 Token 不过期失效(server/cmd/auth-server/main.go)。
fail-closed:未配置就绝不监听
fail-closed 的核心思想是:出问题时宁可不可用,也绝不暴露。Lunar Tear 在 Admin Webhook 上贯彻了这一点,admin.go 的注释与代码明确写道:
如果
LUNAR_ADMIN_TOKEN未设置或为空,监听器根本不会绑定——新部署永远不会暴露一个未认证的端点。
三层防线叠加:
- 🔒无 Token = 无端口:环境变量未设置时,8082 端口上什么都没有,连扫描器都找不到端点;
- 🛡️默认回环:
--admin-listen默认127.0.0.1:8082,只有运维者显式改成0.0.0.0才会对外暴露; - ⏱️恒定时间比较:即使端口暴露,Token 猜测也无法利用响应时间差异。
Docker 部署同样延续此默认:compose 文件将容器内0.0.0.0:8082仅映射到宿主机的127.0.0.1:8082,且LUNAR_ADMIN_TOKEN从.env注入(server/docker-compose.yaml)。
其他值得学习的安全细节 📝
- bcrypt 存储密码:注册时密码经
bcrypt.GenerateFromPassword加盐哈希后入库,绝不存明文(server/internal/auth/store.go); - 统一错误文案:登录失败一律返回 "Invalid username or password.",避免暴露"该用户不存在",防止账号枚举(handlers.go);
- 注册开关
--no-register:开放运营前可关闭自助注册,改用 server/cmd/register-account/ 工具受控建号,实现"白名单式开服"; - 模板自动转义:登录页与 OAuth 重定向页均使用 Go
html/template,自动防止 XSS(handlers.go)。
部署检查清单 ✅
| # | 检查项 | 预期状态 |
|---|---|---|
| 1 | LUNAR_ADMIN_TOKEN是否已设置 | 未设置时 8082 端口不监听(fail-closed) |
| 2 | --admin-listen绑定地址 | 默认127.0.0.1:8082,公网部署勿改0.0.0.0 |
| 3 | auth-server 的--secret | 重启时复用同一密钥,否则存量 Token 全部失效 |
| 4 | 注册策略 | 稳定运营期建议开启--no-register |
| 5 | Token 有效期 | 客户端 Token 24 小时,到期需重新登录 |
更多端口、环境变量与命令行参数的完整对照,可查阅 README.md 的 "Live Master Data Reload" 一节。
小结:Lunar Tear 的安全设计体现了一套清晰的原则——最小暴露(无 Token 不监听、默认回环)、强认证(HMAC 签名 + 恒定时间比较)、弱默认(注册可一键关闭)。这些模式对任何需要暴露管理端点的自建服务项目,都值得借鉴。
【免费下载链接】lunar-tear
Private server research project for a certain discontinued mobile game
相关推荐
如何免费解锁 WeMod 专业版:Wand-Enhancer 本地补丁与手机远程面板实操
如何免费解锁 WeMod 专业版:Wand Enhancer 本地补丁与手机远程面板实操 Wand Enhancer 是完全开源的本地补丁工具:扫描本机 WeM
桌面应用前端gsd-core Worktree 清理安全加固:基于 per-wave Manifest 的失败关闭(fail-closed)机制解析
gsd core Worktree 清理安全加固:基于 per wave Manifest 的失败关闭(fail closed)机制解析 导读 本文聚焦 GSD
AOS Capsule 安全设计详解:信任边界、边缘校验、Fail-Closed 语义、资源限制与对抗式评审
AOS Capsule 安全设计详解:信任边界、边缘校验、Fail Closed 语义、资源限制与对抗式评审 本文以 AOS Community Edition
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考