Appearance
异地登录提醒怎么做?给账号安全加一道锁
"您的账号在异地登录"——这种提醒大家应该都收到过。作为一个开发,你可能也想过给自己产品做一套。这篇文章讲讲怎么用IP归属地实现"异地登录提醒",以及最容易做砸的几个地方。
原理一句话
用户登录时,记录IP归属地(省份/城市)。下次登录如果"变化异常",就发提醒或者要求二次验证。就这么简单。
基础版:登录时记录位置
python
def on_login(user_id, ip):
info = query_ip(ip) # 查IP9
location = None
if info:
location = f"{info.get('prov')} {info.get('city')}"
# 存到用户表
save_login_location(user_id, location, ip, time.now())判断"异地":三个层次
层次1:按城市判断(最粗糙)
python
def check(user_id, ip):
info = query_ip(ip)
new_loc = f"{info.get('prov')} {info.get('city')}"
old_loc = get_last_location(user_id)
return new_loc != old_loc这个方案会误报炸。原因:用户出差、搬家、甚至IP抖动,都会触发。我第一版就是这么做的,结果被用户投诉"天天提醒异地登录"。
层次2:常用IP池 + 时间窗口
改进:维护每个用户的"常用IP池",只有"新IP + 新地区 + 短时间内异常"才告警。
python
from collections import deque
def is_risky(user_id, ip, info):
pool = get_ip_pool(user_id) # 该用户常用的IP集合
if ip in pool:
return False # 常用IP,安全
# 不常用IP,再看地区
new_city = f"{info.get('prov')} {info.get('city')}"
if new_city in get_common_cities(user_id):
return False # 地区常去,不告警
# 从来没去过的地区 + 不常用IP -> 风险
return True要点:把"常用"记成池子,别用"上一次"做唯一参照。这样用户出差去常去的地方,就不会乱弹。
层次3:结合频率和时段
更精细的:同一IP 10分钟内换了N个账号登录,或凌晨异地登录,加权重。这些组合起来,告警准确率高很多。
告警之后做什么
别只弹个提醒就完事,要给用户选择:
- 低风险:站内提醒"您的账号近期在XX登录过";
- 中风险:要求短信/邮箱验证码;
- 高风险:直接冻结异常会话,要求改密码。
最容易踩的坑
1. 移动用户被天天误伤。 手机流量IP飘得厉害,真正常用户也会被判定"异地"。对策是:对移动网络用户放宽标准,或者干脆只对"IP类型异常"才告警(比如平时都是ISP家庭宽带,突然从IDC机房登录)。
2. 忽略代理。 攻击者用代理,IP常变。这种单靠地区判断没用,要结合设备指纹。IP只是第一道防线,别指望它全挡住。
3. 只记"上一次"。 记住,用常用池,别用上一次。
代码骨架
python
def login_security_check(user_id, ip):
info = query_ip(ip)
if not info:
return "allow" # 查不到,放行(或走其他验证)
if is_risky(user_id, ip, info):
return "verify" # 要求二次验证
update_ip_pool(user_id, ip) # 记入常用池
return "allow"一句忠告
异地登录提醒这个功能,宁可不弹,也不要乱弹。弹多了,用户会关闭通知,甚至觉得产品有问题。把误报率压下去,比什么都重要。