Files.md令牌系统深度解析:TOKENS_SALT与sha256如何保障同步安全
2026/9/16 23:10:52 网站建设 项目流程

Files.md令牌系统深度解析:TOKENS_SALT与sha256如何保障同步安全

【免费下载链接】files.md🌱 Private, quiet space for thinking. Simple app for .md files.项目地址: https://gitcode.com/GitHub_Trending/fi/files.md

Files.md 是一款专注.md文件同步的轻量应用,主打"私密、安静的思考空间"。它的多端同步能力背后,是一套简洁却严谨的令牌认证系统:通过TOKENS_SALT加盐的 SHA-256 哈希存储、一次性令牌(one-time token)交换与 IP 封禁机制,在几乎没有数据库的情况下守护你的笔记安全。本文将带你从源码视角读懂这套设计。

为什么 Files.md 需要令牌机制

Files.md 的核心场景是:你在浏览器 PWA 中编辑 markdown 笔记,服务器负责在多设备间同步文件。任何一次同步请求都必须先证明"我是这个用户"。

传统做法是用户名密码 + 数据库会话,但 Files.md 走了一条极简路线:令牌即身份,哈希文件名即数据库。整个认证逻辑集中在 tokens.go 中,不到 300 行代码就完成了全部鉴权。

令牌生成:32字节真随机数

所有令牌都由genToken()生成:

  • crypto/rand(操作系统级加密随机源)读取32 字节
  • 转为 64 位十六进制字符串作为令牌

32 字节意味着 256 位密钥空间——暴力穷举在物理上不可行。这是整个安全体系的第一块基石:令牌本身无法被猜测。

核心机密:TOKENS_SALT 与 sha256 加盐存储

这是本文的主角。永久令牌从不以明文落盘,服务器执行的关键操作在hashToken()中:

token + TokensSalt拼接后做 SHA-256 哈希,用哈希值的十六进制串作为文件名,文件内容只存用户 ID。

也就是说,磁盘上的令牌"数据库"长这样:

/opt/files.md/tokens/<sha256(token + salt)>.md→ 内容为一串用户 ID

盐(TOKENS_SALT)在这里起三个作用:

  1. 防止离线爆破:令牌目录一旦泄露,攻击者拿到的是哈希文件名。由于令牌是 32 字节真随机数,即便算出对应明文也无意义——但加盐后,攻击者连"这个文件名对应什么哈希输入"都无法跨服务器迁移复现
  2. 防止彩虹表:不同服务器使用不同的TOKENS_SALT(通过环境变量注入,见 config.go),同样的令牌在不同实例上产生完全不同的文件名,无法预计算
  3. 隔离多实例:官方文档 docs/e2e-tests.md 明确说明了这一机制——令牌文件按sha256(标识 + salt)命名

源码注释里还有一句硬核的量化说明:按每秒 10 亿次 SHA-256 哈希的速率,暴力破解需要约 10^60 年(见 tokens.go)。

一次性令牌:Bot 链接设备的"入场券"

Files.md 配有一个 Telegram Bot,你可以直接在聊天中记录想法。要打通 Bot 与 Web 应用,需要设备绑定

  1. 在 Bot 中发送/app,服务端调用GenOneTimeToken()生成一次性令牌,并拼出?token=xxx的 Web 链接(bot.go)
  2. 该令牌仅存于内存oneTimeTokensmap),有效期只有10 分钟
  3. 浏览器打开链接后,前端把令牌 POST 到/issuePermanentToken接口,服务端校验后立即从内存删除——令牌一次性使用,无法重放(app.js)
  4. 交换成功后,服务器签发永久令牌并写入 HttpOnly Cookie

一次性令牌"短命 + 内存 + 用后即焚",永久令牌"长寿 + 落盘 + 哈希化",两者职责分离,是教科书级的设计。

永久令牌:HttpOnly Cookie 守护 10 年

交换成功后签发的永久令牌写入 Cookie,配置十分讲究(tokens.go):

  • HttpOnly: true—— JavaScript 无法读取,XSS 偷不走令牌
  • Secure: true—— 仅 HTTPS 传输
  • SameSite: None—— 支持 api 域与 app 域分离的双域部署
  • MaxAge10 年—— 基本"一次绑定,长期有效"

每次请求经过tokenMiddleware中间件:先查 Cookie(兼容旧的 Authorization 头),用findUserID()sha256(token + salt)文件名读盘,拿到用户 ID 后才放行同步请求。完整的同步时序可参阅 docs/sync-flow.md。

防御攻击者:IP 封禁与"只留指纹"的日志

Files.md 的令牌系统还有两层容易被忽略的防御:

🛡️ 无效令牌即封 IP:携带无效令牌的请求返回 401,同时该 IP 被拉黑10 分钟;期间再来的请求直接 429,不再触碰业务逻辑。这是对暴力试探的直接遏制。

🛡️ 日志永不记录令牌明文:调试日志 tokens_dbg.go 会把每次鉴权失败追加到/tmp/auth,但对令牌只做tokenFingerprint()处理——记录长度和 SHA-256 前 8 位。源码注释直白地解释:哪怕 8 个字符的前缀,也足以大幅收窄暴力破解空间,而指纹足以关联同一次攻击。日志本身不会成为新的泄露面。

自建服务器:如何正确配置 TOKENS_SALT

如果你打算自部署(详见 docs/your-own-server.md),盐值是必填项。官方推荐的生成方式:

make init_server host=user@example.com salt=$(head -c 32 /dev/urandom | base64)

Makefile 会将该值注入 systemd 服务的Environment=TOKENS_SALT=$(salt)配置(见 Makefile),随后通过.env文件被 config.go 读取。三条部署建议:

  • ✅ 盐值必须是高熵随机串,不要用密码、日期这类可猜测内容
  • ✅ 盐值丢失 = 所有已签发令牌文件"失配",所有设备需重新绑定,务必备份
  • ⚠️ 迁移服务器时,tokens目录与盐值需一起迁移(docs/your-own-server.md 的迁移章节专门提到了打包tokens.tar.gz

总结:小系统里的大智慧

Files.md 的令牌系统用不到 300 行 Go 代码回答了"无数据库如何安全认证"的问题:

设计点实现安全收益
令牌生成32 字节crypto/rand256 位熵,不可猜测
落盘存储sha256(token + TOKENS_SALT)文件名明文不落盘,防离线爆破与彩虹表
设备绑定10 分钟一次性令牌,用后即焚链接泄露窗口极短,不可重放
CookieHttpOnly + Secure免疫 XSS 窃取
暴力防御无效令牌封 IP 10 分钟试探成本直线上升
日志审计仅记录哈希指纹日志不泄露秘密

它证明了一件事:安全不必靠复杂度堆砌。理解 server/sync/tokens.go 之后,你也能在自己的小项目里复刻这套"加盐哈希 + 一次性交换"的轻量认证方案。

【免费下载链接】files.md🌱 Private, quiet space for thinking. Simple app for .md files.项目地址: https://gitcode.com/GitHub_Trending/fi/files.md

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询