之前发过一篇介绍 yuyu WebSafe 的文章,反响还不错,有不少朋友接入使用。最近这段时间一直在持续迭代,今天发布 v7.0,这个版本我觉得可以说是从「能用的 Demo」正式变成了「生产可用的系统」。
这篇文章主要讲这次更新了什么,以及背后的一些设计考虑。
日后不会 发小版本的更新记录 只有大版本更新才会发文章
小版本更新请看文档站
为什么要重构
坦白说,之前的版本有很多问题是我后来才发现的,有些还挺严重。罗列几个最典型的:
会反复跳转验证页的 Bug
这个问题困扰了我很久。用户明明已经验证通过了,刷新页面又跳回验证页,循环往复。排查下来发现原因不止一个:
一是 Token 生成时就把 JTI 写入了已用列表,导致第一次去服务端验签就返回「已使用」,Cookie 被判定无效,又触发跳转。
二是之前版本做了 IP 绑定,用户在 WiFi 和 4G 之间切换(或者运营商动态 IP)就会 ip_mismatch,Token 失效,又跳转。
三是图片代理请求(4张角色图片并发加载)没有及时释放 Session 文件锁,导致验证请求被阻塞超时。
这些问题单独看都不严重,但加在一起就是「用户体验极差」。
sessionStorage 的选择失误
某个版本我把验证状态的存储从 Cookie 改成了 sessionStorage,本意是想让每次打开新标签页都重新验证(持续保护)。但实际效果是:关闭标签页重开就要重验、多个标签页之间状态不共享、手机 App 内置浏览器每次都要验证……完全不可用。这个版本改回 Cookie 了。
缺少生产环境必要的工具
之前只有核心的验证逻辑,没有:
- 服务健康检查(不知道 GD 扩展有没有、data/ 目录能不能写)
- 验证统计(不知道每天有多少人验证、通过率多少)
- IP 封禁(遇到高频刷请求没办法处理)
- 紧急关闭开关(系统出问题时只能改代码)
v7.0 主要更新
新增文件
这次加了不少新文件,每个都有具体用途:
算数验证改成图片 换了新题目
config.php — 所有配置集中在这一个文件,部署时只需要改这里,不用翻其他文件找配置项。SECRET_KEY、管理密码、白名单域名、角色库都在这里。
token.php — 比 safe.php 更轻量的 PHP 接入库。safe.php 功能比较全,token.php 专注做一件事:验证 Token。一行代码守卫页面:
require 'token.php';
yuyu_require();
也可以直接当 API 用:GET token.php?token=xxx 返回 {"valid":true}。
logout.php — 主动注销验证状态。之前没有这个,用户没有办法「退出」。现在支持三种调用方式:跳转链接、PHP 函数调用、AJAX 请求,可选同时吊销服务端 JTI(防 Token 被他人重用)。
bypass.php — 紧急放行开关。验证系统出问题时,不需要改代码、不需要删文件,访问这个页面输入管理密码就能快速关闭验证放行所有用户,设置有时效(最长1小时自动关闭)。safe.php 和 token.php 里都加了对这个开关的检测。
health.php — 服务健康检查。列出所有依赖项的状态:PHP 版本、GD 扩展、data/ 目录权限、Session 功能、Token 生成/验证……支持 JSON 格式,可以接入监控系统。还会自动创建 data/.htaccess 防止数据文件被直接访问。
stats.php — 详细统计和管理。每日/累计验证次数、通过率、IP 黑名单(手动封禁/解封)、高频请求预警、访问日志查看、JTI 紧急清空。用每日 token 鉴权,不需要单独的密码。
Bug 修复
这次修了很多问题,挑几个重要的说:
反复跳转问题:根本解决了。Token 生成时不再预写 JTI,只在真正消耗(consume=1)时才写;Cookie 复用时只做本地格式和过期检查,不调服务端、不消耗 JTI;移除 IP 绑定,网络切换不影响验证状态。
图片加载问题:img 请求现在会在读完 Session 后立即 session_write_close(),4张图片并发加载不再阻塞其他请求。
sessionStorage → Cookie:改回 Cookie,24小时有效,多标签页共享,关闭重开不需要重验。
验证页体验:加了骨架屏(图片格子有固定高度,加载时不抖动)、图片失败占位符、加载失败重试按钮、锁定倒计时(不再只显示「X分钟后重试」)、fetch 超时控制(网络慢时不会一直转圈)。
yuyu.php 的一堆问题:Let’s Encrypt 证书续签路径(.well-known)被拦截、bypass/health/logout 没有被排除、URL 里的 token 参数没有重定向清除(会暴露在服务器日志里)、WordPress 多站点冲突等,都在这版修了。
安全加固
- 管理员密码改为 bcrypt hash 存储,不再明文
- 管理员登录后执行
session_regenerate_id(true),防 Session Fixation 攻击 data/目录自动创建.htaccess,禁止直接访问数据文件- HMAC 签名验证使用常数时间比较,防时序攻击(一直都有,这次确认保留)
现在的文件结构
yuyu-v7/
├── config.php ← 只改这里
├── api.php ← 后端核心
├── index.html ← 验证页面
├── safe.php ← PHP 接入(完整版)
├── token.php ← PHP 接入(极简版)
├── yuyu.php ← 零配置全站防护
├── logout.php ← 注销验证
├── bypass.php ← 紧急放行
├── health.php ← 健康检查
├── stats.php ← 统计管理
├── verify-client.js ← JS 接入(4种模式)
├── yuyu.js ← JS 接入(极简版)
├── how-to.html ← 接入文档
└── README.md
math.php 渲染数学验证
data.php 目录修复
Password.php 生成密码
接入方式没有变化
对于已经接入的朋友,更新只需要替换文件,接入代码不需要改。
静态网站:
<script src="https://ovo.yuyu09.com/verify-client.js"></script>
PHP 网站:
require 'token.php';
yuyu_require();
完整接入文档:ovo.yuyu09.com/how-to.html
后记
这个项目从最初的 demo 写到现在,改了很多遍,踩了很多坑。有些问题是我自己用的时候发现的,有些是朋友反馈的,有些是代码写完之后静下心来仔细看才发现的。
目前觉得 v7.0 是一个相对稳定、可以放心用在生产环境的版本。如果你在使用中遇到任何问题,欢迎在评论里告诉我。











评论(0)
暂无评论