mcpField
S
sast-missingauth

sast-missingauth

github.com/utkusen安全1.3k69 次安装5 天前更新
代码仓库

关于 sast-missingauth

sast-missingauth 是用于检测缺少身份验证和功能级授权失效的代码安全评估 Skill。它要求先准备架构摘要,再引导 Agent 梳理端点与权限控制、分批核查并汇总结果。

主要功能

  1. 01梳理端点与权限
  2. 02检测身份验证缺失
  3. 03核查角色检查
  4. 04分批审查端点
  5. 05汇总评估结果

适用场景

  1. 01查找未要求登录的敏感端点
  2. 02检查管理路由是否执行角色校验
  3. 03核查路由中间件是否覆盖处理程序

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/utkusen/sast-skills --skill sast-missingauth

安装后在 Claude Code 中输入/sast-missingauth确认已加载。

详细介绍

缺失身份验证与函数级授权失效检测

你正在进行有针对性的安全评估,以查找代码库中缺失身份验证和函数级授权失效漏洞。此技能采用由子 Agent 执行的三阶段方法:侦察(梳理端点和权限系统)、分批验证(每批并行检查 3 个端点的身份验证和授权)以及汇总(整合各批次结果,形成最终报告)。

前提条件:sast/architecture.md 必须存在。如果不存在,请先运行分析技能。


此技能涵盖的内容

缺失身份验证

端点执行敏感操作,但完全不需要登录——任何匿名 HTTP 请求都能触发该操作。

函数级授权失效

端点要求身份验证(用户必须已登录),但不检查已通过身份验证的用户是否拥有调用该函数所需的角色或权限。典型示例:普通用户调用仅限管理员使用的 API。

此技能不涵盖的内容

不要与以下问题混淆:

  • IDOR / 水平权限提升:已通过身份验证的用户 A 通过更改 ID 访问用户 B 的资源。此技能涵盖的是垂直权限提升和未经过身份验证的访问。
  • JWT 弱点:令牌签名或验证存在缺陷(由 sast-jwt 涵盖)。
  • 业务逻辑缺陷:价格篡改、工作流绕过——这些是其他类型的问题。

漏洞类别

类别 1:未经身份验证的敏感端点

端点会修改数据、返回私人信息或执行管理操作,但不要求身份验证。

GET /api/admin/users          → returns full user list, no token needed
DELETE /api/admin/users/5     → deletes a user, no token needed
POST /api/settings/smtp       → updates server config, no token needed
类别 2:已通过身份验证,但缺少角色检查

端点要求有效会话或令牌,但不执行角色或权限检查。任何已通过身份验证的用户,无论其角色如何,都能调用管理员或特权功能。

Regular user sends:
DELETE /api/admin/users/5
Authorization: Bearer <regular_user_token>
→ Server deletes the user without checking if the caller is an admin
类别 3:授权不完整或可绕过

存在授权逻辑,但可以绕过:

  • GET 处理程序中存在角色检查,但对应的 DELETE/POST 处理程序中没有
  • 角色检查取决于攻击者可控的请求标头或参数
  • 已注册中间件,但路由在中间件生效前就已挂载

可防止漏洞的授权模式

如果发现以下模式,端点很可能不存在漏洞:

1. 路由组上同时使用身份验证和角色检查中间件

// Express: all /admin routes protected
router.use('/admin', auth, requireRole('admin'));
router.delete('/admin/users/:id', deleteUser);   // protected by above

// Flask-Login + custom decorator
@app.route('/admin/users')
@login_required
@admin_required
def list_users(): ...

2. 声明式角色注解(Java / Spring)

@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/api/admin/users/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) { ... }

3. 在处理程序中执行敏感操作前检查角色

# Django
@login_required
def delete_user(request, user_id):
    if not request.user.is_staff:
        return HttpResponseForbidden()
    User.objects.filter(id=user_id).delete()
    return HttpResponse(status=204)

4. 将中间件门控应用于整个前缀

// Chi router — admin group protected
r.Group(func(r chi.Router) {
    r.Use(AdminOnly)
    r.Delete("/admin/users/{id}", deleteUser)
})

5. 策略/门控对象

// Laravel Gate
Gate::define('admin-action', fn($user) => $user->role === 'admin');
// In controller
$this->authorize('admin-action');

易受攻击与安全示例

Python — Django
# VULNERABLE: No authentication at all
def list_all_users(request):
    users = User.objects.values('id', 'email', 'is_staff')
    return JsonResponse(list(users), safe=False)

# VULNERABLE: Authenticated but no role check
@login_required
def delete_user(request, user_id):
    User.objects.filter(id=user_id).delete()
    return HttpResponse(status=204)

# SECURE
@login_required
def delete_user(request, user_id):
    if not request.user.is_staff:
        return HttpResponseForbidden()
    User.objects.filter(id=user_id).delete()
    return HttpResponse(status=204)
Python — Flask
# VULNERABLE: No auth decorator
@app.route('/admin/users')
def list_users():
    return jsonify([u.to_dict() for u in User.query.all()])

# VULNERABLE: Login required but no role check
@app.route('/admin/users/<int:user_id>', methods=['DELETE'])
@login_required
def delete_user(user_id):
    user = User.query.get_or_404(user_id)
    db.session.delete(user)
    db.session.commit()
    return '', 204

# SECURE
@app.route('/admin/users/<int:user_id>', methods=['DELETE'])
@login_required
def delete_user(user_id):
    if current_user.role != 'admin':
        abort(403)
    user = User.query.get_or_404(user_id)
    db.session.delete(user)
    db.session.commit()
    return '', 204
Node.js — Express
// VULNERABLE: No auth middleware
router.get('/api/admin/users', async (req, res) => {
    const users = await User.find({});
    res.json(users);
});

// VULNERABLE: Auth middleware present but no role check
router.delete('/api/admin/users/:id', auth, async (req, res) => {
    await User.findByIdAndDelete(req.params.id);
    res.sendStatus(204);
});

// SECURE
const requireAdmin = (req, res, next) => {
    if (req.user.role !== 'admin') return res.sendStatus(403);
    next();
};
router.delete('/api/admin/users/:id', auth, requireAdmin, async (req, res) => {
    await User.findByIdAndDelete(req.params.id);
    res.sendStatus(204);
});
Ruby on Rails
# VULNERABLE: No before_action
def destroy
    User.find(params[:id]).destroy
    head :no_content
end

# VULNERABLE: Authenticated but no admin check
before_action :authenticate_user!
def destroy
    User.find(params[:id]).destroy
    head :no_content
end

# SECURE
before_action :authenticate_user!
before_action :require_admin

def destroy
    User.find(params[:id]).destroy
    head :no_content
end

private

def require_admin
    head :forbidden unless current_user.admin?
end
Java — Spring Boot
// VULNERABLE: No security annotation
@DeleteMapping("/api/admin/users/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
    userRepo.deleteById(id);
    return ResponseEntity.noContent().build();
}

// VULNERABLE: Authenticated but wrong role
@DeleteMapping("/api/admin/users/{id}")
@Secured("ROLE_USER")  // any user can call this
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
    userRepo.deleteById(id);
    return ResponseEntity.noContent().build();
}

// SECURE
@DeleteMapping("/api/admin/users/{id}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
    userRepo.deleteById(id);
    return ResponseEntity.noContent().build();
}
Go
// VULNERABLE: No auth middleware on route
r.Delete("/admin/users/{id}", deleteUser)

// VULNERABLE: Auth middleware but no role check in handler
r.With(AuthMiddleware).Delete("/admin/users/{id}", deleteUser)

func deleteUser(w http.ResponseWriter, r *http.Request) {
    id := chi.URLParam(r, "id")
    db.DeleteUser(id)  // no role check
    w.WriteHeader(http.StatusNoContent)
}

// SECURE
r.Group(func(r chi.Router) {
    r.Use(AuthMiddleware)
    r.Use(AdminOnlyMiddleware)
    r.Delete("/admin/users/{id}", deleteUser)
})
PHP — Laravel
// VULNERABLE: No auth middleware
Route::delete('/admin/users/{id}', [AdminController::class, 'destroy']);

// VULNERABLE: Auth but no role gate
Route::middleware('auth')->delete('/admin/users/{id}', [AdminController::class, 'destroy']);

// SECURE
Route::middleware(['auth', 'role:admin'])->delete('/admin/users/{id}', [AdminController::class, 'destroy']);

// SECURE (using Gate in controller)
public function destroy($id) {
    Gate::authorize('admin-action');
    User::findOrFail($id)->delete();
    return response()->noContent();
}
C# — ASP.NET Core
// VULNERABLE: No authorization attribute
[HttpDelete("api/admin/users/{id}")]
public async Task<IActionResult> DeleteUser(int id) {
    await _userService.DeleteAsync(id);
    return NoContent();
}

// VULNERABLE: [Authorize] but no role
[Authorize]
[HttpDelete("api/admin/users/{id}")]
public async Task<IActionResult> DeleteUser(int id) {
    await _userService.DeleteAsync(id);
    return NoContent();
}

// SECURE
[Authorize(Roles = "Admin")]
[HttpDelete("api/admin/users/{id}")]
public async Task<IActionResult> DeleteUser(int id) {
    await _userService.DeleteAsync(id);
    return NoContent();
}

执行

此技能通过子 Agent 分三个阶段运行。将 sast/architecture.md 的内容作为上下文传递给所有子 Agent。

阶段 1:侦察 — 梳理端点和权限系统

启动一个子 Agent,并提供以下指令:

目标:完整梳理 (1) 所有应用端点/路由及其当前的身份验证/授权状态,以及 (2) 角色/权限系统。将结果写入 sast/missingauth-recon.md。

背景:你将获得项目架构摘要。利用它了解技术栈、框架、路由定义以及身份验证/授权策略。

搜索内容:

  1. 所有路由/端点定义 — 收集每个 HTTP 处理程序、REST 端点、GraphQL mutation/query、RPC 方法或 WebSocket 处理程序:
    • Express/Koa:router.get/post/put/delete/patch/use
    • Django:urlpatterns、path()、re_path()
    • Flask:@app.route、@blueprint.route
    • Rails:routes.rb — get、post、resources、namespace
    • Spring:@GetMapping、@PostMapping、@RequestMapping、@DeleteMapping、@PutMapping
    • Go/Chi:r.Get、r.Post、r.Delete、r.Handle
    • Laravel:Route::get/post/put/delete
    • FastAPI:@router.get/post/put/delete
    • ASP.NET:[HttpGet]、[HttpPost]、[HttpDelete]、[HttpPut]
  2. 当前应用的身份验证中间件和装饰器:
    • 确认使用的模式:@login_required、auth 中间件、[Authorize]、authenticate_user!、JWT 验证中间件、会话检查
    • 记录它们应用于哪些路由或路由组
    • 记录明确排除身份验证的路由(例如 except: [:index, :show])
  3. 角色/权限系统 — 确认角色的定义和检查方式:
    • 角色常量/枚举:ROLE_ADMIN、'admin'、UserRole.ADMIN、is_staff、is_superuser
    • 权限装饰器:@admin_required、@roles_required、@PreAuthorize、requireRole()
    • 中间件:AdminOnly、requireAdmin、role:admin
    • Policy/Gate/Ability 对象:Gate::define、Policy、CanCanCan、Pundit
    • 处理程序中的检查:if user.role != 'admin'、if not current_user.is_admin
  4. 需要标记的敏感/特权端点 — 任何满足以下条件的端点:
    • 路径前缀包含 /admin、/management、/internal、/api/admin、/superadmin、/system、/ops
    • 执行用户管理操作:创建/更新/删除用户、更改角色、为其他用户重置密码
    • 管理应用配置:设置、功能标志、SMTP、密钥、环境变量
    • 访问财务/账单数据:所有用户的发票、付款、订阅
    • 触发系统操作:向所有用户发送电子邮件、运行后台任务、清除缓存
    • 返回汇总或敏感数据:所有用户、所有订单、审计日志、错误日志
  5. 记录每个端点的信息:
    • 是否存在身份验证中间件/装饰器
    • 是否存在角色/权限检查
    • 处理的 HTTP 方法
    • 是否读取、写入或删除数据

忽略内容:

  • 预期公开的端点:登录、注册、密码重置请求、公开内容(博客文章、商品列表)
  • 静态资源服务、健康检查端点(/health、/ping、/status)

输出格式 — 写入 sast/missingauth-recon.md:

# Missing Auth Recon: [Project Name]

## Permission System Summary
- Roles identified: [list roles, e.g. admin, moderator, user]
- Auth mechanism: [JWT / session / API key / OAuth]
- Auth decorators/middleware: [list names, e.g. @login_required, auth, requireAdmin]

## Endpoint Inventory

### 1. [Endpoint name / description]
- **File**: `path/to/file.ext` (lines X-Y)
- **Endpoint**: `METHOD /path`
- **Operation**: [read / write / delete / admin-action]
- **Auth present**: [yes / no]
- **Role check present**: [yes / no / partial]
- **Code snippet**:

[route registration + handler signature]


[Repeat for each endpoint]
阶段 2:验证 — 检查身份验证和授权(分批进行)

阶段 1 完成后,读取 sast/missingauth-recon.md,并将端点清单拆分为每批最多 3 个端点(即 Endpoint Inventory 下编号为 ### N. 的各项)。为每个批次并行启动一个子 Agent。每个子 Agent 只验证分配给自己的端点,并将结果写入各自的批次文件。

分批流程(由你这个编排者执行,而非子 Agent):

  1. 读取 sast/missingauth-recon.md,统计 Endpoint Inventory 下编号端点章节的数量(### 1.、### 2. 等)。
  2. 将它们划分为每批最多 3 个端点。例如,8 个端点 → 3 个批次(1–3、4–6、7–8)。
  3. 对于每个批次,从 recon 文件中提取这些端点章节的完整文本。
  4. 并行启动所有批次子 Agent,并只向每个子 Agent提供分配给它的端点。
  5. 每个子 Agent 将结果写入 sast/missingauth-batch-N.md,其中 N 是从 1 开始的批次编号。
  6. 从 sast/architecture.md 中确定项目的主要语言/框架,并从上方的“易受攻击与安全示例”部分中仅选择匹配的示例。例如,如果项目使用 Python/Django,则只包含“Python — Django”(以及在相关时包含 Flask)示例。在下方 [TECH-STACK EXAMPLES] 所示位置,将这些选定示例纳入每个子 Agent 的指令中。

向每个批次子 Agent 提供以下指令(替换为该批次对应的值):

目标:检查以下端点是否存在缺少身份验证和函数级授权失效漏洞。将结果写入 sast/missingauth-batch-[N].md。

分配给你的端点(来自侦察阶段):

[在此粘贴分配给你的端点章节全文,并保留原始编号]

背景:你将获得项目的架构摘要。请利用它了解中间件的执行顺序、角色定义和身份验证模式。

缺少身份验证/函数级授权失效——需要检查的内容:

  • 缺少身份验证:执行敏感操作时不需要登录/会话/令牌。
  • 函数级授权失效:需要身份验证,但特权端点没有角色/权限检查(垂直权限提升)。

本技能不涵盖的内容——请勿在此处报告:

  • IDOR/水平权限提升:用户 A 通过更改 ID 访问用户 B 的资源 → 由 IDOR 技能覆盖。
  • JWT 加密/验证漏洞 → 由 sast-jwt 覆盖。

可避免漏洞的授权模式——如果发现以下模式,端点可能是安全的:

  1. 在路由组上同时使用身份验证和角色检查中间件(例如,router.use('/admin', auth, requireRole('admin')))
  2. 声明式角色注解(例如,@PreAuthorize("hasRole('ADMIN')"))
  3. 在处理程序中执行敏感操作前检查角色
  4. 对整个前缀设置中间件门控(例如,使用 AdminOnly 的 Chi r.Group)
  5. 强制执行特权操作的策略/门控对象

适用于本项目技术栈的易受攻击与安全示例:

[TECH-STACK EXAMPLES]

对每个分配的端点进行评估:

  1. 身份验证检查——是否要求有效的登录/会话/令牌?
    • 此路由或其父级路由组上是否有身份验证中间件、装饰器或守卫?
    • 追踪中间件链——确认身份验证中间件在处理程序之前运行,而不是之后
    • 检查路由是否意外地挂载在受身份验证保护的路由组之外
  2. 角色/权限检查——如果端点具有特权,是否验证了角色或权限?
    • 查找:is_admin、is_staff、role == 'admin'、hasRole('ADMIN')、@PreAuthorize、requireRole、can?(:manage, ...)、Gate::allows、authorize('admin-action')
    • 确认每种 HTTP 方法都会执行检查——即使 GET 受保护,DELETE 也可能没有保护
    • 检查角色比较是否反向,或是否能被轻易绕过
  3. 边缘情况:
    • 检查是否由用户可控的标头、参数或查询字符串决定是否执行检查
    • 检查路由组受门控保护,但特定路由是否通过 except 列表被排除
    • 是否存在访问同一功能的其他未授权路径(例如,内部 API 别名)?
    • 中间件是否仅在某些环境中生效(例如,在测试模式下跳过)?
  4. 特权识别:
    • 端点路径是否表明其属于管理员/特权操作(/admin/、/manage/、/internal/)?
    • 操作是否会影响其他用户的数据、系统配置或汇总记录?
    • 只要其中任一项为是,就应有角色/权限检查

分类:

  • 易受攻击:不需要身份验证,或者虽已通过身份验证,但特权端点完全没有角色检查。
  • 可能易受攻击:存在身份验证和/或角色检查,但似乎不完整、可绕过或应用不当(例如,角色错误、HTTP 方法错误、条件性跳过)。
  • 不易受攻击:已正确实施身份验证和角色/权限检查。
  • 需要人工审查:无法有把握地判定(例如,中间件链复杂、角色动态加载、授权委托给服务层)。

输出格式——写入 sast/missingauth-batch-[N].md:

# 缺少身份验证批次 [N] 结果

## 发现

### [易受攻击] 端点名称
- **文件**:`path/to/file.ext`(第 X-Y 行)
- **端点**:`METHOD /path`
- **问题**:[缺少身份验证/特权操作缺少角色检查]
- **影响**:[未通过身份验证或权限较低的攻击者可以执行的操作]
- **证据**:[展示路由定义和处理程序——指出缺少的检查]
- **修复建议**:[具体修复方法——添加身份验证中间件、添加角色装饰器等]
- **动态测试**:

[curl 命令或分步说明,用于在运行中的应用上确认此问题。 对于缺少身份验证:展示不带令牌的请求成功。 对于缺少角色检查:展示普通用户令牌对管理员端点的请求成功。 使用 <REGULAR_USER_TOKEN>、<ADMIN_ENDPOINT> 等占位符。]


### [可能易受攻击] 端点名称
- **文件**:`path/to/file.ext`(第 X-Y 行)
- **端点**:`METHOD /path`
- **问题**:[检查不完整之处]
- **风险**:[此问题仍可能被利用的原因]
- **证据**:[展示存在弱检查/部分检查的代码路径]
- **修复建议**:[具体修复方法]
- **动态测试**:

[curl 命令或分步说明,用于在运行中的应用上确认此发现。]


### [不易受攻击] 端点名称
- **文件**:`path/to/file.ext`(第 X-Y 行)
- **端点**:`METHOD /path`
- **保护措施**:[说明其保护方式——身份验证中间件加角色装饰器/@PreAuthorize/Gate 等]

### [需要人工审查] 端点名称
- **文件**:`path/to/file.ext`(第 X-Y 行)
- **端点**:`METHOD /path`
- **不确定性**:[自动化分析无法判定状态的原因]
- **建议**:[人工检查的内容]
阶段 3:合并 — 汇总批次结果

在所有阶段 2 批次子 Agent 完成后,读取每个 sast/missingauth-batch-*.md 文件,并将它们合并到一个 sast/missingauth-results.md 文件中。由你(编排者)直接完成此操作——无需子 Agent。

合并步骤:

  1. 读取所有 sast/missingauth-batch-1.md、sast/missingauth-batch-2.md……文件。
  2. 收集每个批次文件中的所有发现并合并为一个列表,同时保留原始分类和所有详细字段。
  3. 汇总所有批次的总数,用于执行摘要。
  4. 按照以下格式将合并后的报告写入 sast/missingauth-results.md:
# Missing Auth/Authz Analysis Results: [Project Name]

## Executive Summary
- Endpoints analyzed: [total across all batches]
- Vulnerable: [N]
- Likely Vulnerable: [N]
- Not Vulnerable: [N]
- Needs Manual Review: [N]

## Findings

[All findings from all batches, grouped by classification:
 VULNERABLE first, then LIKELY VULNERABLE, then NEEDS MANUAL REVIEW, then NOT VULNERABLE.
 Preserve every field from the batch results exactly as written.]
  1. 写入 sast/missingauth-results.md 后,删除所有中间文件:sast/missingauth-recon.md 和 sast/missingauth-batch-*.md。

重要提醒

  • 读取 sast/architecture.md,并将其内容作为上下文传递给所有子 Agent。
  • 阶段 2 必须在阶段 1 完成后运行——它依赖侦察输出。
  • 阶段 3 必须在所有阶段 2 批次完成后运行——它依赖所有批次输出。
  • 每个子 Agent 的批次大小为 3 个端点。如果总共有 1–3 个端点,则使用单个子 Agent。如果有 10 个,则使用 4 个子 Agent(3+3+3+1)。
  • 并行启动所有批次子 Agent——不要按顺序逐个运行。
  • 每个批次子 Agent 只接收侦察文件中分配给它的端点文本,而不是整个侦察文件。这样可以让每个子 Agent 的上下文保持精简、聚焦。
  • 重点关注垂直权限提升(用户 → 管理员)和未认证访问。水平权限提升(用户 A → 用户 B 的资源)由 IDOR 技能负责。
  • 身份验证(你是谁)和授权(你是否有权执行此操作)是两个独立的问题——两者都要检查。
  • 中间件顺序很重要:在路由处理程序之后注册的中间件无法保护该路由。
  • 如果某个 HTTP 方法(例如 DELETE)缺少身份验证或角色检查,即使 GET 受到保护,也构成完整漏洞。
  • 如有疑问,应归类为“需要人工审查”,而不是“无漏洞”。在安全评估中,漏报比误报更糟糕。
  • 注意路由分组:use('/admin', adminRouter) 模式会保护 adminRouter 中的所有路由,但挂载在该分组之外的路由不会受到保护。
  • 清理中间文件:写入最终的 sast/missingauth-results.md 后,删除 sast/missingauth-recon.md 和所有 sast/missingauth-batch-*.md 文件。

评论

支持 Markdown