SuperAPI AI 工具集

access-control-patterns

安全与审计

查看项目

更新于 10-15 09:44

技能介绍

用途

该技能用于防止用户访问其无权访问的数据或操作。资料指出,失效的访问控制是 OWASP A01,因为它是最常见的严重 Web 漏洞:用户 A 可以读取用户 B 的发票、更改另一个租户的设置,或通过猜测 ID 调用管理端点。

核心原则

  • 默认拒绝——除非显式标记为公开,否则没有路由是公开的
  • 服务端检查授权——永远不要信任隐藏按钮或客户端检查
  • 按用户或租户限定每个查询——永远不要仅凭原始 ID 获取
  • 使用集中式策略——避免分散的 if (user.role === 'admin') 检查
  • 将角色与权限分离——角色是捆绑包,权限是操作
  • 审计敏感决策——记录被拒绝和特权操作

漏洞模式:IDOR

资料给出不安全直接对象引用(IDOR)的错误与正确写法。

错误示例:

app.get('/api/invoices/:id', async (req, res) => {
  const invoice = await db.invoice.findUnique({ where: { id: req.params.id } });
  res.json(invoice); // Any logged-in user can read any invoice by guessing ID
});

正确示例:

app.get('/api/invoices/:id', requireAuth, async (req, res) => {
  const invoice = await db.invoice.findFirst({
    where: {
      id: req.params.id,
      tenantId: req.user.tenantId,
    },
  });

  if (!invoice) return res.status(404).json({ error: 'Not found' });
  res.json(invoice);
});

当不应暴露资源是否存在时,返回 404 而不是 403。

企业授权模型

对每个受保护操作使用以下决策顺序:

  1. 用户是否已认证?
  2. 账户是否处于活动状态且未被暂停?
  3. 用户是否在被访问的租户/工作区内?
  4. 用户是否具有所需权限?
  5. 资源是否属于用户的租户?
  6. 是否存在对象级条件?(所有者、分配用户、审批状态)
  7. 该操作是否应记录审计日志?

RBAC 模式

资料给出基于角色的访问控制示例:

type Role = 'owner' | 'admin' | 'member' | 'viewer';
type Permission =
  | 'invoice:read'
  | 'invoice:create'
  | 'invoice:update'
  | 'invoice:delete'
  | 'user:invite'
  | 'billing:manage';

const ROLE_PERMISSIONS: Record<Role, Permission[]> = {
  owner: ['invoice:read', 'invoice:create', 'invoice:update', 'invoice:delete', 'user:invite', 'billing:manage'],
  admin: ['invoice:read', 'invoice:create', 'invoice:update', 'user:invite'],
  member: ['invoice:read', 'invoice:create'],
  viewer: ['invoice:read'],
};

function hasPermission(role: Role, permission: Permission): boolean {
  return ROLE_PERMISSIONS[role]?.includes(permission) ?? false;
}

ABAC 模式

基于属性的访问控制增加对象级条件:

interface AuthContext {
  userId: string;
  tenantId: string;
  role: Role;
  permissions: Permission[];
}

interface Invoice {
  id: string;
  tenantId: string;
  ownerId: string;
  status: 'draft' | 'sent' | 'paid';
}

function canUpdateInvoice(user: AuthContext, invoice: Invoice): boolean {
  if (invoice.tenantId !== user.tenantId) return false;
  if (!hasPermission(user.role, 'invoice:update')) return false;
  if (invoice.status === 'paid') return false;
  if (user.role === 'member' && invoice.ownerId !== user.userId) return false;
  return true;
}

各框架实现模式

Node.js / Express 中间件

资料提供 requireAuth、requirePermission 中间件以及路由示例,权限检查失败时记录审计日志并返回 403。

Cloudflare Workers 模式

资料提供 requireAuth、requirePermission 以及按租户限定查询的 getTenantScopedInvoice 示例。

Laravel Policy 模式

资料提供 InvoicePolicy 的 view 与 update 方法,以及控制器中 authorize 调用。并强调始终为路由模型绑定或全局作用域添加租户限定:

protected static function booted()
{
    static::addGlobalScope('tenant', function (Builder $builder) {
        if (auth()->check()) {
            $builder->where('tenant_id', auth()->user()->tenant_id);
        }
    });
}

Python FastAPI 模式

资料提供 require_permission 依赖以及按租户限定查询的 update_invoice 示例。

数据库行级安全

对于 PostgreSQL,在数据库层也强制租户隔离:

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON invoices
  USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- Set this per request/transaction
SELECT set_config('app.current_tenant_id', 'tenant-uuid-here', true);

RLS 不能替代应用授权,但当开发者忘记租户过滤时,它可以减少影响范围。

管理路由保护

管理路由需要更强的控制:

  • 将 admin:* 权限与用户角色分离
  • 管理操作要求 MFA
  • 敏感变更要求近期认证
  • 审计记录所有管理读写
  • 永远不要依赖前端路由隐藏
  • 尽可能阻止来自未知 IP 的管理访问

资料给出 requireAdminAction 组合中间件示例。

访问控制审计清单

  • 每个受保护路由都有认证中间件
  • 每个敏感操作都有权限检查
  • 每个资源查询都按 tenantId 或 userId 限定
  • 租户拥有的资源不使用原始 ID 查找
  • 用户无法通过更改 URL ID 访问另一个租户的数据
  • 前端检查在服务端重复
  • 管理路由要求显式管理权限
  • 管理操作要求 MFA 或近期重新认证
  • 被拒绝的访问尝试记录审计日志
  • 未授权时不泄露资源是否存在
  • 角色和权限集中定义
  • 多租户应用存在数据库 RLS 或等效防护
  • 测试覆盖跨租户访问尝试

必需测试

每个多租户项目必须包含这些测试,资料给出示例:

it('prevents user from reading another tenant invoice', async () => {
  const tenantAInvoice = await createInvoice({ tenantId: 'tenant-a' });
  const tenantBUser = await createUser({ tenantId: 'tenant-b' });

  const response = await request(app)
    .get(`/api/invoices/${tenantAInvoice.id}`)
    .set('Authorization', `Bearer ${tokenFor(tenantBUser)}`);

  expect(response.status).toBe(404);
});

PDPA 2024 后果

资料指出,失效的访问控制是造成可报告个人数据泄露的最快方式。如果一个客户可以访问另一个客户的个人数据,则开发者未能实现基本授权和租户隔离。根据 PDPA 2024 Seksyen 5(1) 和 5(2),这可能触发最高 RM1,000,000 罚款或 3 年监禁。

适用场景与限制

该技能适用于需要防止越权访问、多租户数据隔离、管理路由保护和安全审计的 Web 应用开发。资料未提供该技能的安装命令、收费信息、平台支持范围或具体使用步骤,这些内容暂未提供。