8***@qq.com
8***@qq.com
  • 发布:2026-10-26 17:12
  • 更新:2026-10-26 17:12
  • 阅读:50

医药电商|药店商城小程序管理后台 常驻图形验证码 + 滑块验证 + 超次锁定

分类:uni-app

管理后台登录是医药电商系统的核心入口,一旦管理员账号被暴力破解,商品、订单、资质等敏感数据将面临严重风险。本文记录我们在后台登录模块中落地的三层防护方案:常驻图形验证码 + 失败触发滑块 + 账号/IP 双维度锁定,重点分享几个关键的安全设计决策。
一、整体防护分层
1,登录接口的安全校验按成本从低到高依次执行:
2,锁定状态前置判断:账号或 IP 已被锁定,直接拒绝;
3,图形验证码常驻校验:每次登录必填,阻断自动化脚本;
4,滑块验证条件触发:连续失败达到阈值后强制要求;
5,账号密码核验:最后才进入核心认证逻辑。
把高拦截率、低成本的校验放前面,既提升安全性,也减少无效计算。核心流程代码如下:

public function login()  
{  
    [$account, $password, $captchaVerification, $imgcode] =  
        $this->request->postMore(['account', 'pwd', 'captchaVerification', 'imgcode']);  

    // 1. 前置锁定校验(账号 + IP 任一命中即拒绝)  
    if ($this->isLocked($account)) {  
        return app('json')->fail('登录失败次数过多,请15分钟后再试');  
    }  

    // 2. 图形验证码常驻校验  
    if (!app()->make(Captcha::class)->check($imgcode)) {  
        return app('json')->fail('验证码错误');  
    }  

    // 3. 滑块验证(失败触发)  
    if ($captchaVerification && !$this->checkSlide($captchaVerification)) {  
        return app('json')->fail('滑块验证失败', ['login_captcha' => 1]);  
    }  

    // 4. 账号密码核验  
    $result = $this->services->login($account, $password, 'admin');  
    if (!$result) {  
        $failCount = $this->recordFail($account); // 记录失败次数  
        $needSlide = $failCount >= 2 ? 1 : 0;     // 失败2次后触发滑块  
        return app('json')->fail('账号或密码错误', ['login_captcha' => $needSlide]);  
    }  

    $this->clearFail($account); // 登录成功,清除失败计数  
    return app('json')->success($result);  
}

二、三个关键设计决策

  1. 验证码失败不计入登录失败次数
    这是整个方案里最容易踩坑的点。如果验证码错误也计入失败次数,攻击者可以故意输错验证码来消耗失败额度,无需知道密码就能把管理员账号锁死——典型的账号锁定型拒绝服务攻击。
    因此我们只把"验证码正确,但账号或密码错误"计为一次有效失败:
    
    // 图形验证码校验失败 → 直接返回,不调用 recordFail()  
    if (!app()->make(Captcha::class)->check($imgcode)) {  
    return app('json')->fail('验证码错误');  
    }  

// 只有账号密码校验失败才计入
if (!$result) {
$failCount = $this->recordFail($account);
}

  1. IP 阈值远高于账号阈值
    账号维度设为 5 次,IP 维度设为 50 次。企业环境中多个管理员可能共用一个公网 IP,IP 阈值过低会导致"一个人输错几次,全办公室被锁"的误伤。账号做精准防护,IP 做兜底防护,各司其职。
const LOGIN_FAIL_MAX      = 5;   // 账号维度:精准锁定  
const LOGIN_FAIL_IP_MAX   = 50;  // IP 维度:兜底防护,防误伤  
const LOGIN_FAIL_LOCK_TIME = 900; // 锁定15分钟,到期自动解锁
  1. 登录成功后只清账号计数,不清 IP 计数
    如果登录成功就清除 IP 计数,攻击者可以通过"先暴力破解一批账号,再用正确密码登录其中一个"来重置 IP 防护。保留 IP 计数,堵住这条旁路。
private function clearFail(string $account): void  
{  
    CacheService::delete('login_fail_admin_' . md5($account));  
    // 注意:不清除 IP 维度计数,防止被利用来重置兜底防护  
}

三、前后端协同
后端返回数据中携带 login_captcha 字段,前端据此决定是否弹出滑块:
login_captcha 值 前端行为
0 不弹滑块,仅提示错误
1 弹出滑块验证,用户必须完成才能再次提交
四、小结
防护维度 策略 核心收益
图形验证码 常驻必填 阻断自动化脚本
滑块验证 失败2次触发 区分人机,不打扰正常用户
账号锁定 5次/15分钟 精准防护暴力破解
IP 锁定 50次/15分钟 兜底防护,防误伤

真正的安全往往藏在那些"看起来多此一举"的细节里——验证码失败不计数的设计,恰恰是防住最容易被忽视的攻击面。

0 赞 关注 分享

要回复文章请先登录或注册