我用 AI 辅助重构了遗留项目的认证模块:从明文存储到 OAuth 2.0 的安全升级

接手一个老项目,发现用户密码居然是明文存储,认证逻辑散落在 7 个文件中。借助 AI 工具分析遗留代码、设计安全方案并渐进式迁移,最终在不中断业务的前提下完成了安全升级。

接盘即惊吓:明文密码和散落的认证逻辑

年初接手了一个内部管理系统,技术栈是 PHP 5.6 + jQuery,没有框架,没有 ORM,用户认证直接调 MySQL。当我看到数据库 users 表里明晃晃存着 password 字段,值是用户注册时填的原始密码时,后背一凉------这个系统已经跑了四年,有两百多个企业客户在用。

更头疼的是认证逻辑散落在至少 7 个文件里:

  • login.php 处理用户名密码校验
  • check_auth.php 在每个页面顶部 include 做 session 检查
  • logout.php 清理 session
  • reset_password.php 管理员直接改数据库
  • api/auth.php 给几个简单的 API 做 token 校验(token 也是明文存在表里)
  • 还有几个页面直接写了 if ($_SESSION['user_id'] == '') 这种硬编码判断

没有任何加密、没有密码强度要求、没有登录失败限制、没有 CSRF 防护。 这个模块不仅是技术债,更是一个安全定时炸弹。

重构的目标很明确:用 bcrypt 存储密码、引入 JWT 做无状态认证、统一认证入口、加基础防护。但老系统没有测试,贸然重写万一漏了某个边缘逻辑就会影响线上业务。我需要先彻底理解现有逻辑 ,再设计安全方案 ,最后渐进式迁移。这个过程中 AI 工具帮了大忙。

第一步:用 AI 从遗留代码中提取认证状态机

传统做法是手动翻 7 个文件,画流程图。这次我把所有相关代码文件拖进 Cursor,用它的项目级索引功能,然后问:

"分析 login.php、check_auth.php、logout.php、reset_password.php、api/auth.php,提取所有与用户认证相关的逻辑,输出以下内容:

  1. 认证流程(从登录到 session 校验的完整路径)
  2. 所有涉及密码操作的代码位置和操作类型(读取、写入、校验、重置)
  3. 各文件之间的依赖关系
  4. 潜在的安全漏洞(按严重程度排序)"

Cursor 基于 Claude Sonnet 4 模型,在几十秒内给出了分析报告。关键发现:

  • 密码在 4 个地方被读取/写入,全部是明文。
  • session 校验逻辑不一致:有的地方检查 $_SESSION['user_id'],有的检查 $_SESSION['login'],还有一个页面自己维护了一套 cookie 校验。
  • API 的 token 生成用了 md5(username + 'secret'),可以被预测。
  • 没有密码重置的验证机制,管理员可以直接改任意用户的密码。

这一步帮我省了至少半天的人工梳理时间 ,而且 AI 不会遗漏分散在边角的逻辑------有个 download_report.php 里藏了一句独立的 session 检查,人工排查大概率会漏掉。

第二步:用 AI 设计安全方案并评估风险

搞清现状后,我让 Cursor 帮我设计目标方案:

"基于以上认证逻辑,设计一个安全的认证方案,要求:

  1. 密码用 bcrypt 存储,cost factor 建议值
  2. 使用 JWT 替代 session + API token
  3. 统一的认证中间件
  4. 登录失败次数限制(5 次锁定 30 分钟)
  5. 密码重置必须通过邮箱验证
  6. 输出数据库 schema 变更、API 设计、中间件伪代码"

AI 给出的方案包含:

  • users 表新增 password_hashlogin_attemptslocked_until 字段,保留旧的 password 字段作为过渡。
  • JWT 的 access token 15 分钟过期,refresh token 7 天,存在 httpOnly cookie 中。
  • 中间件用 PSR-7 风格(因为是 PHP),统一校验 Authorization header。
  • 登录失败计数器用 Redis 原子操作,避免并发绕过。

我对方案做了一处重要修改 :AI 建议直接废弃旧 password 字段,我坚持保留作为过渡期兼容------因为还有其他微服务直接读这个字段。这是 AI 不会知道的业务上下文,人的判断仍然不可或缺。

第三步:渐进式迁移------不停机切换认证方式

新旧认证方式需要共存一段时间,既要让新登录逻辑生效,又要保证老 session 和 API 继续工作。我设计了一个双轨运行期:

php 复制代码
// 认证适配器(简化版)
class AuthAdapter {
    // 新用户或已迁移用户走 JWT
    public function authenticate($username, $password) {
        $user = $this->db->getUser($username);
        
        // 优先用 bcrypt 验证已迁移的密码
        if (!empty($user['password_hash'])) {
            if (password_verify($password, $user['password_hash'])) {
                return $this->issueJwt($user);
            }
        }
        
        // 回退到明文验证(仅过渡期)
        if ($password === $user['password']) {
            // 验证成功后立即迁移密码
            $this->migratePassword($user['id'], $password);
            return $this->issueJwt($user);
        }
        
        // 记录失败次数
        $this->recordFailedAttempt($user['id']);
        return false;
    }
    
    // 迁移密码
    private function migratePassword($userId, $plainPassword) {
        $hash = password_hash($plainPassword, PASSWORD_BCRYPT, ['cost' => 12]);
        $this->db->update($userId, [
            'password_hash' => $hash,
            'password' => null  // 清除明文
        ]);
    }
}

这样每个用户首次用明文密码登录后,密码立即被迁移为 bcrypt 并删除明文。整个过程对用户透明。

AI 在这个阶段的作用 :我让 Cursor 帮我找到所有直接读取 password 字段的 SQL 语句和代码(共 11 处),确保迁移逻辑不会漏掉任何读操作。这个搜索人工做容易漏,AI 几秒就扫完了。

第四步:补充安全防护------AI 生成测试用例和防护规则

迁移完成后,AI 帮我做了两件事:

1. 生成安全测试用例

"为新的认证模块生成 PHPUnit 测试用例,覆盖:

  • 正常登录、错误密码、用户不存在
  • 密码迁移逻辑(明文密码首次登录)
  • JWT 过期、篡改、缺失
  • 登录失败锁定(5 次、6 次、锁定后 30 分钟解锁)
  • CSRF token 校验"

AI 生成了 30 多个测试用例,我手动补充了 3 个边缘场景(如并发登录失败计数),全部通过。

2. 配置安全响应头

AI 帮我生成了 Nginx 和 PHP 的安全头配置:

nginx 复制代码
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

迁移结果与数据对比

整个迁移在两周内完成,期间系统正常运行,没有用户反馈登录问题。

指标 重构前 重构后
密码存储方式 明文 bcrypt (cost 12)
认证文件数 7 个 1 个中间件 + 1 个 service
登录失败限制 5 次/30 分钟
密码重置流程 管理员直接改库 邮箱验证链接
API 认证 固定 token (MD5) JWT (15 分钟过期)
安全测试覆盖 0% 87%

最重要的是,这次重构让我对遗留系统的安全升级有了一套可复用的方法论:AI 做分析和方案设计,人做关键决策和验证,渐进式迁移不中断业务。

几个关键经验

  1. 不要一次性重写:双轨运行虽然代码丑一点,但安全。我跑了两周双轨,确认所有用户都完成密码迁移后,才删除了旧逻辑。
  2. AI 分析遗留代码的效率远超人工 :尤其是找"隐式依赖"------比如那个藏在 download_report.php 里的独立 session 检查,AI 帮我一网打尽。
  3. 安全方案要结合业务上下文:AI 建议全量迁移,但我保留了过渡期兼容老系统。AI 没有你的业务知识,方案必须人审。
  4. 渐进迁移的核心是"自动升级":在用户无感知的情况下完成密码升级,这比发通知让所有人改密码的用户体验好得多。

如果你也在维护遗留系统,建议花半天时间让 AI 帮你做一次安全审计,你会发现自己一直不敢动的代码其实没那么可怕。


你接手过最吓人的遗留系统是什么样的?有没有在重构时踩过什么坑?欢迎评论区交流。

相关推荐
用户34232323763171 小时前
数据质量与异常检测——当采集系统学会了“怀疑“
后端
Dilee1 小时前
Spring AI 核心链路拆解:ChatClient、Prompt、Advisor、ChatModel 到底怎么串起来?
后端
Java知识技术分享1 小时前
opencode安装ui-ux-pro-max和frontend-ui-ux技能
人工智能·ui·个人开发·ai编程·ux
虎妞05001 小时前
AI 编程助手横评:Cursor vs Copilot vs Claude Code
ai编程·开发工具·cursor·github copilot·claude code
来让爷抱一个2 小时前
MonkeyCode Agent深度解析:AI如何自主完成从编码到部署
开源·ai编程·monkeycode
无风听海2 小时前
在 ASP.NET Core 开发环境中为自定义域名签发受信任的自签名证书—HSTS 启用后的完整实践
windows·后端·asp.net
阿伟AI说2 小时前
Codex 桌面版接入国产模型系列二:Codex++
java·开源软件·ai编程·腾讯云ai代码助手
无风听海2 小时前
深入理解 ASP.NET Core 中的UseHsts()
后端·asp.net
学编程的小程2 小时前
DISTINCT 的“惯性陷阱“:当去重操作沦为性能累赘
后端