1. 什么是越权访问?

越权访问指的是用户通过非法手段访问本不属于自己的资源或操作权限,比如普通用户访问管理员页面、A用户读取B用户的数据等。


2. PHP项目中常见的越权场景

  • 用户未登录就访问需要登录的页面
  • 普通用户访问管理员功能
  • 用户访问/操作其他用户的数据(如修改他人订单、查看他人资料等)

3. 防护思路

1. 身份认证

  • 判断用户是否已登录(如session、token校验)
  • 未登录用户直接跳转到登录页或返回401

2. 权限校验

  • 判断当前用户是否有权限访问该资源或操作
  • 检查用户角色(如admin、user、guest等)
  • 检查资源归属(如只能操作自己的数据)

3. 后端强校验

  • 前端校验不可靠,所有权限校验必须在后端实现!

4. 具体实现方法

1. 登录认证(Session/Token)

session_start();
if (!isset($_SESSION['user_id'])) {
    // 未登录
    header('Location: login.php');
    exit;
}

2. 角色权限校验

// 假设$_SESSION['role']存储了用户角色
if ($_SESSION['role'] !== 'admin') {
    die('无权限访问');
}

3. 资源归属校验

// 例如:用户只能操作自己的订单
$order_id = $_GET['order_id'];
$user_id = $_SESSION['user_id'];
$order = getOrderById($order_id);

if ($order['user_id'] != $user_id) {
    die('越权访问!');
}

这段PHP代码的意思是:防止用户操作不属于自己的订单,保护数据安全,防止越权访问。

下面逐行解释:


$order_id = $_GET['order_id'];
  • 从URL参数(GET请求)中获取订单ID,比如用户访问 order.php?order_id=123,那么 $order_id 就是 123
$user_id = $_SESSION['user_id'];
  • 从当前会话(Session)中获取当前登录用户的ID。这个ID是在用户登录后存储在Session里的,代表“你是谁”。
$order = getOrderById($order_id);
  • 调用自定义函数 getOrderById,根据订单ID从数据库查出订单的详细信息(比如订单属于谁、订单内容等)。
if ($order['user_id'] != $user_id) {
    die('越权访问!');
}
  • 检查订单的 user_id(订单属于哪个用户)和当前登录用户的ID是否一致。
  • 如果不一致,说明这个订单不是当前用户的,用户试图操作别人的订单,属于“越权访问”。
  • 于是程序终止,并输出“越权访问!”。

总结

这段代码的作用是:

  • 只允许订单的主人操作自己的订单。
  • 防止用户通过修改URL参数等方式,访问或操作别人的订单数据。
  • 增强系统安全性,防止数据泄露和非法操作。

一句话解释:

只有订单的主人才能操作自己的订单,其他人操作会被拦截并提示“越权访问!”。

4. RBAC权限控制(推荐)

  • RBAC(基于角色的访问控制)是企业级项目常用的权限管理方式
  • 可以用数据库表设计角色、权限、用户-角色、角色-权限等关系

5. 中间件/统一拦截

  • 框架(如Laravel、ThinkPHP、Yii等)都支持中间件或行为拦截
  • 在中间件里统一做权限校验,避免每个控制器都写重复代码

5. 常见PHP框架的做法

  • Laravel:使用中间件(Middleware)和Gate/Policy
  • ThinkPHP:使用行为/中间件和Auth类库
  • Yii:使用AccessControl过滤器

6. 其他安全建议

  • 接口返回统一的无权限提示,不要泄露敏感信息
  • 日志记录所有越权尝试,便于追踪和报警
  • 定期安全测试和代码审计

7. 真实案例

错误做法:

// 只判断是否登录,未判断资源归属
if (!isset($_SESSION['user_id'])) {
    die('请登录');
}
// 直接操作order_id,可能越权
updateOrderStatus($_GET['order_id']);

正确做法:

if (!isset($_SESSION['user_id'])) {
    die('请登录');
}
$order = getOrderById($_GET['order_id']);
if ($order['user_id'] != $_SESSION['user_id']) {
    die('越权访问!');
}
updateOrderStatus($order['id']);

这段PHP代码的意思是:防止未登录用户和越权用户操作订单,确保只有订单的主人才能操作自己的订单。下面逐行解释:


if (!isset($_SESSION['user_id'])) {
    die('请登录');
}
  • 作用:判断用户是否已经登录。
  • 原理$_SESSION['user_id'] 存储了当前登录用户的ID。如果没有这个值,说明用户未登录。
  • 处理:未登录就终止程序,提示“请登录”。

$order = getOrderById($_GET['order_id']);
  • 作用:根据前端传来的 order_id,从数据库获取订单信息。
  • 原理getOrderById() 是一个自定义函数,返回订单的详细信息(如订单所属用户、状态等)。

if ($order['user_id'] != $_SESSION['user_id']) {
    die('越权访问!');
}
  • 作用:判断当前订单是不是属于当前登录用户。
  • 原理:订单表里有 user_id 字段,表示订单归属哪个用户。如果订单的 user_id 和当前登录用户的 user_id 不一致,说明用户在操作别人的订单(越权)。
  • 处理:发现越权行为,终止程序,提示“越权访问!”。

updateOrderStatus($order['id']);
  • 作用:如果前面都通过了校验,说明用户有权操作这个订单,于是执行订单状态更新操作。

总结

这段代码的核心作用是:

  1. 校验用户是否登录(防止未登录操作)
  2. 校验用户是否有权操作该订单(防止越权访问)
  3. 只有校验通过后,才允许操作订单

这样可以有效防止安全漏洞,保护用户数据安全。

总结

  • 所有权限校验必须在后端实现,不能只靠前端!
  • 每次操作都要校验用户身份和资源归属
  • 推荐用RBAC等成熟权限管理方案
  • 利用框架的中间件/拦截器统一处理权限
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐