一、什么是逻辑漏洞?从生活中的例子说起
逻辑漏洞是程序按照设计正常运作,但设计本身有问题,导致可以被人利用的漏洞。
举个生活化的例子:
想象一个游乐园的检票规则:
-
正常规则:1.2米以下儿童免费,以上全票
-
逻辑漏洞:只检查身高,不检查年龄
-
利用方法:高个子孩子弯腰通过,被当作“1.2米以下”
程序中的逻辑漏洞类似:系统按规则运行,但规则有缺陷。
二、常见逻辑漏洞类型与简单实例
1. 越权访问漏洞
场景:学校成绩查询网站
# 有漏洞的代码
def get_score(student_id):
# 直接返回成绩,没检查是不是本人的
score = database.query("SELECT * FROM scores WHERE id = ?", student_id)
return score
# 正常访问:/get_score?id=1001 (查看自己的成绩)
# 漏洞利用:/get_score?id=1002 (看到同学的成绩)
问题:系统认为“登录了就能看所有成绩”,但应该是“只能看自己的成绩”。
实际案例:
2023年某学习App漏洞:
-
小明登录后能看自己成绩:api/score/1001
-
修改数字:api/score/1002 → 看到小红的成绩
-
继续修改:api/score/1003、1004... → 看到全班成绩
修复方法:
def get_score(student_id):
# 先检查是不是自己的成绩
if student_id != current_user.id:
return "无权查看他人成绩"
score = database.query("SELECT * FROM scores WHERE id = ?", student_id)
return score
2. 价格篡改漏洞
场景:网上商城购买商品
正常流程:
1. 选择商品:iPhone手机 价格6999元
2. 点击购买
3. 支付6999元
漏洞利用:
1. 选择商品:iPhone手机
2. 用工具修改价格:6999元 → 1元
3. 支付1元成功购买
为什么会这样?
因为程序员只在前端验证价格:
// 前端代码(用户能修改)
function checkPrice() {
let price = document.getElementById("price").value; // 6999
if (price < 100) { // 前端检查
alert("价格异常");
return false;
}
return true;
}
// 后端代码(忘记验证价格)
function processOrder(price) {
// 这里直接相信前端传来的价格!
chargeUser(price); // 如果price=1,就只收1元
sendProduct(); // 仍然发货
}
现实案例:
2024年某书店网站漏洞:
-
一本原价50元的书
-
用户修改价格为0.01元
-
成功下单,书店损失惨重
正确做法:
def processOrder(frontend_price, product_id):
# 重新从数据库查询真实价格
real_price = database.query("SELECT price FROM products WHERE id = ?", product_id)
# 比较前端价格和真实价格
if abs(frontend_price - real_price) > 0.01: # 允许微小误差
return "价格异常,请刷新页面"
chargeUser(real_price) # 按真实价格收费
sendProduct()
3. 绕过步骤漏洞
场景:注册账号需要4步
正常流程:
1. 填写手机号 → 2. 获取验证码 → 3. 设置密码 → 4. 注册成功
漏洞流程:
用户直接访问第4步的网址 → 跳过验证,注册成功
实例:某App注册漏洞
# 不安全的代码结构
# 步骤1:/register/step1 输入手机号
# 步骤2:/register/step2 输入验证码
# 步骤3:/register/step3 设置密码
# 步骤4:/register/step4 注册完成
# 攻击者发现:
# 直接访问 /register/step4?phone=13800138000&password=123456
# 就能创建账号,跳过验证码验证
修复:每一步都检查上一步是否完成
def step4(request):
# 检查是否完成了前3步
if not request.session.get("step1_done"):
return "请先完成步骤1"
if not request.session.get("step2_done"):
return "请先完成步骤2"
if not request.session.get("step3_done"):
return "请先完成步骤3"
# 只有完成所有步骤才能注册
createAccount()
4. 重复提交漏洞
场景:抽奖活动每人只能抽一次
# 有漏洞的代码
def lucky_draw():
# 检查今天是否抽过奖
if not has_drawn_today(): # 检查:今天没抽过
result = draw() # 抽奖
save_result(result) # 保存结果
return result
return "今天已抽过"
# 攻击方法:快速连续点击10次"抽奖"按钮
# 第1次:检查通过 → 抽奖
# 第2次:在保存结果前,检查还没更新 → 又通过
# 第3次:同样通过...
现实案例:某商场抽奖活动
-
规则:每人每天抽1次
-
漏洞:用户用程序1秒点100次
-
结果:1人抽中100个奖品
修复:用数据库锁防止重复
def safe_lucky_draw(user_id):
# 开始数据库事务
with transaction.atomic():
# 检查并标记"正在抽奖"
if not mark_drawing(user_id): # 原子操作
return "今天已抽过"
result = draw()
save_result(user_id, result)
return result
5. 时间修改漏洞
场景:会员试用3天
def check_vip_trial(user_id):
start_date = get_start_date(user_id) # 从用户手机获取开始时间
current_date = get_current_date() # 从用户手机获取当前时间
if (current_date - start_date) <= 3: # 3天试用期
return True # 还是VIP
else:
return False # 试用结束
# 漏洞利用:
# 用户把手机时间调回1周前
# 系统认为:试用期还有6天
# 结果:永久免费使用VIP
实际案例:多个App的试用漏洞
用户发现:修改手机时间 → 试用期重新计算 → 永远在试用期
修复:使用服务器时间
def check_vip_trial_fixed(user_id):
start_date = get_start_date(user_id) # 从数据库获取
current_date = get_server_date() # 用服务器时间,不用手机时间
if (current_date - start_date) <= 3:
return True
else:
return False
三、如何发现逻辑漏洞?
简单三步法:
第一步:理解正常流程
正常:A → B → C → D
第二步:尝试异常操作
尝试:A → D(跳过B、C)
尝试:C → A(反向操作)
尝试:A → C → B → D(打乱顺序)
第三步:检查是否被阻止
-
如果异常操作成功 → 可能有漏洞
-
如果被阻止 → 比较安全
常见测试点:
-
改数字
-
用户ID:1001 → 1002
-
订单号:20240001 → 20240002
-
商品ID:101 → 102
-
-
改价格
-
总价:100 → 1
-
数量:1 → -1
-
运费:10 → 0
-
-
跳步骤
-
直接访问最后一步
-
跳过验证码
-
跳过密码确认
-
-
重复操作
-
快速点击提交按钮
-
重复使用优惠券
-
重复领取奖励
-
四、如何防御逻辑漏洞?
1. 后端验证一切
原则:前端验证只是为了用户体验,后端验证才是真安全
# 错误:信任前端
def buy_product(product_id, frontend_price):
charge(frontend_price) # 直接收前端的钱
send_product(product_id)
# 正确:后端重新计算
def buy_product_safe(product_id, frontend_price):
# 1. 从数据库查真实价格
real_price = get_real_price(product_id)
# 2. 比较前后端价格
if abs(frontend_price - real_price) > 0.01:
return "价格异常"
# 3. 用真实价格收费
charge(real_price)
send_product(product_id)
2. 每次都要检查权限
def get_user_data(user_id):
# 不检查:任何人都能看
data = database.query("SELECT * FROM users WHERE id = ?", user_id)
return data
def get_user_data_safe(user_id):
# 检查是不是查看自己
if current_user.id != user_id and not current_user.is_admin:
return "无权查看他人信息"
data = database.query("SELECT * FROM users WHERE id = ?", user_id)
return data
3. 使用服务器控制
-
时间用服务器时间,不用用户手机时间
-
编号用随机生成,不用1、2、3、4
-
状态用服务器记录,不用前端传递
4. 重要操作加验证
# 敏感操作前要求再次验证
def change_password(new_password):
# 1. 检查是否已登录(基础)
if not is_logged_in():
return "请先登录"
# 2. 修改密码前要求验证旧密码(加强)
old_password = request.input("old_password")
if not check_password(current_user, old_password):
return "旧密码错误"
# 3. 重要操作可以短信验证(更安全)
if is_sensitive_operation():
sms_code = request.input("sms_code")
if not check_sms_code(current_user.phone, sms_code):
return "短信验证码错误"
# 4. 执行修改
update_password(new_password)
return "修改成功"
5. 记录操作日志
def log_important_action(user, action, detail):
# 记录谁、什么时候、做了什么
log_entry = {
"user_id": user.id,
"action": action, # 如:"修改价格"、"查看他人信息"
"detail": detail, # 如:"从100元改为1元"
"time": get_current_time(),
"ip": get_user_ip()
}
save_to_log(log_entry)
# 异常操作实时告警
if action in ["价格修改", "权限变更", "数据导出"]:
send_alert_to_admin(log_entry)
五、给开发者的安全检查清单
每次写完代码,问自己这些问题:
关于权限:
-
[ ] 用户A能不能访问用户B的数据?
-
[ ] 普通用户能不能做管理员的操作?
-
[ ] 没登录的用户能不能看到登录后才能看的内容?
关于数据:
-
[ ] 价格、数量等数字能不能被用户修改?
-
[ ] 用户能不能跳过必填步骤?
-
[ ] 重复提交会不会有问题?
关于流程:
-
[ ] 能不能从步骤3直接跳到步骤1?
-
[ ] 不完成A,能不能做B?
-
[ ] 操作顺序打乱会怎样?
关于状态:
-
[ ] 已完成的订单能不能再付款?
-
[ ] 已取消的订单能不能再发货?
-
[ ] 用户能不能修改时间相关的限制?
六、给用户的简单建议
即使你不是程序员,也能保护自己:
-
复杂密码:不要用简单密码
-
定期修改:重要密码3个月改一次
-
不同网站不同密码:一个网站泄露,不影响其他
-
警惕异常请求:软件要求奇怪权限时要小心
-
及时更新:保持软件最新版本
-
开启二次验证:密码+手机验证更安全
七、学习资源与道德警示
合法学习途径:
-
在线靶场(合法练习环境)
-
DVWA(Damn Vulnerable Web Application)
-
WebGoat
-
很多大学提供的实验环境
-
-
CTF比赛(夺旗赛)
-
合法的网络安全竞赛
-
在规则内测试技能
-
学习防御方法
-
-
公开漏洞报告
-
看别人怎么发现漏洞
-
学习如何正确报告
-
了解修复方法
-
重要法律警示:
请务必记住:
-
未经授权测试是违法行为
-
测试别人的网站需要书面同意
-
即使是好心帮助,也可能违法
-
-
法律后果严重
-
非法获取数据:3年以下有期徒刑
-
造成损失:赔偿+罚款
-
影响一生:留下犯罪记录
-
-
正确做法:
-
在自家电脑搭建测试环境
-
使用专门练习的靶场
-
获得授权后再测试
-
发现漏洞通过官方渠道报告
-
-
道德选择:
-
用技术保护,而不是攻击
-
当白帽子,不当黑客
-
让网络更安全,而不是更危险
-
如果你是网站所有者:
-
定期检查:检查自己的网站是否有这些漏洞
-
邀请测试:请专业人士帮你找问题
-
设置奖励:鼓励大家通过正规渠道报告漏洞
-
及时修复:发现漏洞尽快修补
总结
逻辑漏洞就像门锁好了但窗户没关,看起来安全其实危险。防御逻辑漏洞的关键是:
-
永远不要相信前端:所有检查在后端再做一次
-
每次都要查权限:每次操作都检查“这个人能不能做这件事”
-
记录重要操作:谁、什么时候、做了什么都要记下来
-
异常操作要告警:价格从100变成1要立即知道
-
简单就是美:逻辑越复杂,漏洞可能越多
记住:安全是一个过程,不是一次性的。今天安全不代表明天也安全,要持续检查、持续改进。
最后提醒:本文所有技术仅用于学习防御。未经授权的测试是违法行为,请一定通过合法途径学习和实践网络安全技术。
用你的技能让网络世界更安全,而不是更危险。每个技术人员都有责任保护用户的安全和隐私。
安全之路,正道而行。

247

被折叠的 条评论
为什么被折叠?



