本文目录导读:

在 PHP 中检测账号异常,通常需要结合多种技术手段进行综合判断,这里整理了一套从基础到高级的完整检测方案,你可以根据业务需求选择适合的层级。
基础行为检测(登录层面)
这是最常用,也是最先应该做的检测。
登录失败次数限制
// 最简单的防暴力破解
public function checkLoginAttempts($username, $ip)
{
$key = 'login_attempts_' . md5($username . $ip);
$count = Redis::get($key);
// 15分钟内连续失败5次
if ($count >= 5) {
// 锁定账号
Redis::expire($key, 900);
throw new \Exception('账号已锁定,请15分钟后再试');
}
// 记录失败次数
Redis::incr($key);
Redis::expire($key, 900);
}
代理/IP安全检查
public function checkIpRisk($ip)
{
$riskList = ['代理IP库', 'VPN', 'TOR节点'];
if (in_array($ip, $this->getBlackListIPs())) {
throw new \Exception('IP地址存在风险');
}
// 如果是海外IP,要求二次验证
if ($this->isOverseasIP($ip)) {
// 触发短信/邮件验证码
}
}
用户设备设备指纹检测(中级)
设备指纹对比
public function checkDeviceConsistency($userId, $deviceFingerprint)
{
$userHistory = UserDevice::where('user_id', $userId)
->orderBy('last_login_at', 'desc')
->get();
// 首次设备登录
if ($userHistory->count() === 0) {
// 标记为"新设备",要求额外验证
return ['status' => 'new_device', 'requires_verification' => true];
}
// 历史设备登录
$isKnown = $userHistory->contains($deviceFingerprint);
if (!$isKnown) {
// 新设备+异地IP =高风险
return ['status' => 'suspicious', 'risk_level' => 'high'];
}
return ['status' => 'normal'];
}
异地登录检测
public function checkLocationAnomaly($userId, $currentLocation)
{
// 获取常用登录地(最近30天)
$commonLocations = LoginLog::where('user_id', $userId)
->where('login_at', '>', now()->subDays(30))
->distinct('city')
->pluck('city');
//判断当前登录地是否在常用列表
if (!$commonLocations->contains($currentLocation['city'])) {
return 'unusual_location';
}
// 地理位置跳跃检测
$lastLogin = LoginLog::where('user_id', $userId)
->latest()
->first();
if ($lastLogin) {
$distance = $this->calculateDistance(
$lastLogin->latitude, $lastLogin->longitude,
$currentLocation['latitude'], $currentLocation['longitude']
);
// 4小时内跨越超过1000km很可疑
$hoursBetween = now()->diffInHours($lastLogin->login_at);
if ($hoursBetween < 4 && $distance > 1000) {
return 'impossible_travel';
}
}
}
风险规则引擎(高级)
实时风险评分
class RiskEngine
{
public function assessRisk($context)
{
$riskScore = 0;
// 设备异常 +30分
if ($context['is_new_device']) {
$riskScore += 30;
}
// 地理位置异常 +30分
if ($context['location_anomaly']) {
$riskScore += 30;
}
// 非常用浏览器 +20分
if (!$context['is_common_browser']) {
$riskScore += 20;
}
// 非常用操作系统 +20分
if (!$context['is_common_os']) {
$riskScore += 20;
}
// 浏览器指纹不完整 +10分
if ($context['incomplete_fingerprint']) {
$riskScore += 10;
}
// 判断风险等级
if ($riskScore >= 70) {
return 'high_risk_locked';
} elseif ($riskScore >= 40) {
return 'medium_risk_challenge';
}
return 'low_risk_normal';
}
}
实时行为监测(高级)
异常操作模式监测
public function detectBehaviorAnomaly($userId)
{
// 1. 点击/操作频率异常(短时间内大量操作)
$actionsPerMinute = ActionLog::where('user_id', $userId)
->where('created_at', '>', now()->subMinutes(1))
->count();
if ($actionsPerMinute > 50) {
return 'bots_behavior_detected';
}
// 2. 页面停留时间异常(0.1秒打开10个页面 = bot)
$pageViewTime = PageLog::where('user_id', $userId)
->avg('time_spent');
if ($pageViewTime < 0.5) {
return 'automated_script_usage';
}
// 3. 非工作时间大量操作(凌晨3点高频操作)
$isNight = now()->hour >= 1 && now()->hour <= 5;
if ($isNight && $actionsPerMinute > 20) {
return 'timing_anomaly';
}
return 'normal_behavior';
}
多因素交叉验证
public function multiFactorVerification($userId, $requestData)
{
$verificationFactors = [];
// 验证邮箱验证码
$emailCheck = EmailVerification::where('user_id', $userId)
->where('code', $requestData['email_code'])
->where('expires_at', '>', now())
->exists();
$verificationFactors['email'] = $emailCheck;
// 验证手机号
$phoneCheck = SmsVerification::where('user_id', $userId)
->where('code', $requestData['phone_code'])
->where('expires_at', '>', now())
->exists();
$verificationFactors['phone'] = $phoneCheck;
// 验证安全令牌(如果绑定)
$tokenCheck = UserSecurityToken::where('user_id', $userId)
->where('token', $requestData['security_token'])
->exists();
$verificationFactors['security_token'] = $tokenCheck;
// 至少通过2个因素才能解封
$passed = collect($verificationFactors)->filter(function($value) {
return $value === true;
})->count() >= 2;
return $passed ? 'verified' : 'unverified';
}
综合实践代码
这是一个整合的账号异常检测服务:
<?php
class AccountGuardService
{
private $redis;
private $blacklistService;
public function __construct()
{
$this->redis = Redis::connection();
$this->blacklistService = new BlacklistService();
}
/**
* 综合检测入口
*/
public function verifyAccountAccess($userId, $loginContext)
{
$detectResults = [];
// 1. 黑名单检测
if ($this->blacklistService->isBlacklisted($loginContext['ip'])) {
$detectResults['response'] = 'blocked';
$detectResults['message'] = '您的IP地址在安全黑名单中,请联系客服';
return $detectResults;
}
// 2. 登录失败次数
$failedAttempts = $this->loginAttempts($userId, $loginContext['ip']);
if ($failedAttempts >= 5) {
$detectResults['response'] = 'blocked';
$detectResults['message'] = '登录失败次数过多,账号已被临时锁定';
return $detectResults;
}
// 3. 设备指纹检查
$deviceResult = $this->checkDeviceFull($userId, $loginContext);
// 4. 位置检测
$locationResult = $this->checkLocationFull($userId, $loginContext);
// 5. 行为模式检测
$behaviorResult = $this->checkBehaviorPattern($userId);
// 6. 综合风险评估
$riskScore = $this->calculateScore([
'device' => $deviceResult,
'location' => $locationResult,
'behavior' => $behaviorResult,
'time' => $this->checkLoginTime()
]);
// 根据风险评分决定是否验证
if ($riskScore >= 80) {
$detectResults['response'] = 'blocked';
$detectResults['message'] = '检测到高安全风险操作,账号已被保护锁定';
} elseif ($riskScore >= 50) {
$detectResults['response'] = 'verification_required';
$detectResults['message'] = '检测到异常登录,需完成多因素验证';
// 强制二次验证
$this->sendVerificationCodes($userId);
} else {
$detectResults['response'] = 'normal';
$detectResults['message'] = '登录环境正常';
}
// 记录审计日志
$this->logSecurityEvent($userId, $loginContext, $detectResults);
return $detectResults;
}
// ... 以上各方法的具体实现
}
关键优化建议
| 优化项 | 说明 |
|---|---|
| 数据持久化 | 异常检测结果应保存到数据库,方便追溯 |
| 告警机制 | 高风险触发时通知管理员(邮件/短信) |
| 机器学习 | 用历史数据训练模型,提高检测准确率 |
| 人工介入 | 对于中风险的场景,支持管理员后台手动审核 |
| 响应层级 | 不同风险等级采取不同措施(提示、验证码、锁定、冻结) |
| 避免误报 | 设置阈值时,加入用户历史行为画像作为参考 |
部署注意事项
- 性能优化:使用
Redis存储频繁变更的检测数据,避免频繁读写数据库 - 隐私合规:设备指纹需符合GDPR等数据隐私法规
- 用户体验:过于严格的检测会导致正常用户流失,需要设置合理的阈值
- 降级策略:当检测服务不可用时,应放行并记录日志,而不是阻止所有访问
这套方案从多维度构建了账号异常检测体系,你可以根据实际需求选择实施,如果还需要更深入的实现细节(如设备指纹生成代码、地理位置计算逻辑等),可以继续探讨。