教程
🛡️

网络安全

Web 安全、渗透测试、密码学与安全合规的系统化教程。

PHP 实战审计:越权、支付篡改与鉴权绕过那些坑

框架层面的洞打完,真正的业务系统里更致命的往往是逻辑漏洞。这篇用贴近真实的 PHP 案例,讲清水平越权、垂直越权、支付金额篡改、验证码/Token 绕过、接口未授权访问等高频逻辑缺陷,以及审计时怎么顺着"身份—权限—关键操作"这条链去挖。

· 更新于 2026-07-19 阅读量 --

命令执行、SQL 注入固然吓人,但在真实业务系统里,逻辑漏洞才是审计的”大头”:它们不报错、不报警,却能让普通用户删光别人的数据、把一百块订单改成一块钱、用别人的账号发消息。这类漏洞黑盒难发现,白盒一审一个准。这一篇用贴近实战的 PHP 案例,带你审逻辑。

本文所有手法仅用于你对自有或已授权的 PHP 代码做安全评估。

水平越权:你能动别人的数据吗

水平越权指”同权限用户,访问/修改了他人的资源”。最常见于”按 ID 操作”的接口:

$id = $_GET['id'];
$sql = "DELETE FROM orders WHERE id = $id";
// 没有判断 $id 是否属于当前登录用户

攻击者把 id 改成别人的订单号就删掉了。审计要点:凡是出现”根据用户传入的 ID 做查询/删除/修改”的地方,必须确认代码里有没有 AND user_id = 当前用户 这样的归属校验。没校验,就是水平越权。

垂直越权:普通用户干了管理员的事

垂直越权指”低权限用户访问了高权限功能”。常见于两套判断没对齐:

  • 页面入口判断了权限(没登录跳登录页),但接口没判断,攻击者直接调接口就绕过前端。
  • 用了 if ($_SESSION['role'] == 'admin') 做判断,但某些接口忘了加,或用了不一致的变量名。

审计时,把所有”管理员才该做的操作”(删用户、改配置、导出全量数据)列出来,逐个确认对应的接口是否也做了权限校验,而不是只看页面。

支付与金额:数字可信吗

电商、充值类系统,金额和数量是重灾区:

  • 前端传金额:下单时商品价格由前端表单提交,后端没按商品 ID 重新查库核价,攻击者改 price=0.01 就低价买单。
  • 数量为负/小数quantity=-1 导致退款变加钱,或 quantity=0.5 绕过库存整数校验。
  • 优惠券/积分重复用:同一优惠券可多次叠加,或并发请求下重复抵扣。

正确做法是:金额、单价一律以服务端按商品 ID 查到的为准,数量做正整数与库存校验,优惠逻辑幂等。审计时搜下单、支付回调相关代码,看有没有”信任了前端传来的金额/数量”。

验证码与 Token 绕过

  • 验证码:图形验证码只在前端比对、或后端校验后不销毁 session,导致可重复使用;短信验证码未限频、可爆破(如 6 位纯数字无锁定)。
  • CSRF Token:表单有 token 但后端接口没校验,或校验逻辑写在了不该写的地方(如只在 GET 校验)。
  • 重置密码:找回密码的 token 可预测(如 md5(用户名+时间戳))、或重置链接里 uid 可控,导致改掉别人的密码。

审计时对这些”身份确认”环节,重点看校验是否真的在服务端执行、是否可被复用或预测

接口未授权访问

很多系统把鉴权写在某个基类或中间件里,但总有”漏网之鱼”:新写的接口忘了继承基类、或路由配置把某些路径排除在鉴权外(except 列表配错)。攻击者扫一遍接口,就能找到不需要登录就能调的”后门”。审计时把路由表和鉴权中间件对一遍,特别留意 loginuploadexportconfig 这类敏感接口是否真的被保护。

一个完整的审计思路演示

假设审计一个”用户中心”,可以这样走:

  1. 登录后抓包,看请求里带什么身份标识(uidtokensession)。
  2. 找到”修改资料""查看订单""删除地址”等接口,读它们的代码。
  3. 对每个接口问:它从哪里取”当前用户身份”?这个身份能不能被请求参数覆盖?关键操作前有没有归属校验?
  4. 发现”删除地址”接口用 GETaddress_id 且没校验归属 → 水平越权,记下。
  5. 动态验证:登录 A 账号,把请求里的 address_id 改成 B 账号的,看是否成功删除。

这就是”身份—权限—关键操作”三连问,逻辑漏洞基本都藏在这条链上。

常见坑点小结

  • 只在前端做权限/金额判断,后端没兜底。
  • == 比较权限标识,可被类型转换绕过。
  • 删除/修改接口用 GET 且可被 CSRF,或没校验归属。
  • 验证码、Token 在服务端不校验或可被复用。
  • 新接口忘了挂鉴权中间件。

逻辑漏洞的挖掘心法与自测

逻辑漏洞难在”没有报错提示”,所以更靠心法。给你三条实操建议,外加几个自测问题,帮你判断自己有没有审到位:

心法一:把自己当成”想占便宜的用户”。 黑盒时你会试”改个参数能不能少付钱”,白盒时也一样——凡是涉及钱、权限、身份的判断,都假想”如果我是攻击者,怎么让这段判断失效”。带着这个念头读代码,越权、篡改、绕过会自动跳出来。

心法二:追”信任边界”。 系统的信任边界在哪?前端传来的全是不可信的,服务端内部才是可信的。每看到一个值从”不可信”流向”关键操作”,就停下来问:中间有没有被校验?校验在服务端还是前端?

心法三:别被”有判断”骗了。 代码里有 if 判断权限不等于真校验了。要看判断的条件对不对、比较是不是严格、能不能被参数覆盖、有没有其他入口绕过了这个判断。

自测题(对着你审的系统问自己):

  1. 把请求里的用户标识改成别人的,关键操作还能成功吗?
  2. 不登录直接调”管理员接口”,会被拦吗?
  3. 下单时把价格改成负数或零,后端会按传来的收钱吗?
  4. 验证码用完一次后,还能用同一个再提交吗?
  5. 删资源的接口用 GET 且没校验归属,能被跨站请求伪造打中吗?

这五题但凡有一题答案是”会/能/没拦”,就说明还存在逻辑漏洞。把它们当成每次审计的必检清单,漏掉的概率会大幅下降。

写在逻辑审计之后

逻辑漏洞的修复往往不靠一个函数,而靠”把校验写在对的地方”。审计者交付时,与其甩一句”有越权”,不如明确指出”删除接口缺少归属校验,建议在 SQL 中增加 owner_id 条件”。你多写一句根因和改法,开发就少绕一小时弯。白盒审计的价值,正体现在这种把模糊风险变成具体可修项的能力上。

这一篇你该记住的

  • 逻辑漏洞不报错不报警,却是业务系统最致命的一类,白盒审计优势明显。
  • 水平越权:操作资源时没校验”这条数据是不是当前用户的”,按 ID 操作必查归属。
  • 垂直越权:页面判了权限但接口没判,或接口漏挂鉴权中间件,要按”操作—接口”逐对核对。
  • 支付篡改:金额/单价必须服务端按商品 ID 重查,数量做正整数与库存校验,优惠要幂等。
  • 验证码、Token、密码重置要在服务端校验且不可复用、不可预测。
  • 审计逻辑漏洞的万能三连问:身份从哪来 → 权限怎么判 → 关键操作前校验了没

PHP 的语言基础、框架审计和业务逻辑漏洞都讲到了,但审几万行代码光靠肉眼太慢。下一篇我们专门讲 PHP 代码审计工具——Seay、Semgrep、Xdebug 这些兵器怎么用,帮你把体力活交给工具、把判断留给自己。