name: unauthorized-access description: 未授权访问检测 — 未登录用户可访问敏感接口、管理功能或核心数据的风险;适用于公开 API、管理端点与内部服务暴露场景。 when-to-use: 当需要验证未登录用户是否可访问敏感接口、管理功能或核心数据时 allowed-tools: bash,read_file,list_files,rg user-invocable: false
未授权访问检测
成因引用
未授权访问成因:source(任何请求——包含无凭证 / 空凭证 / 伪造 header)→ sink(应受保护端点的认证决策点:路由认证中间件、handler 入口的鉴权调用、网关路由表的 public/protected 分类、静态资源 Server 的目录映射)。该端点应受保护但实际"漏挂中间件 / 路由前缀错配 / 兜底拒绝缺失 / 仅前端隐藏"导致未认证可达。详见同根目录 pentest/web-security-testing/SKILL.md 漏洞成因图谱 · 未授权访问行(不在本 skill 重复成因)。
触发线索(基线检查项)
以下是已知的常见未授权访问触发线索,作为基线起点而非必检硬清单。结合目标代码与上下文动态调整:
- 适用且已完成 → 标注
[x] done - 明确不适用 → 标注
[-] n/a (原因),原因要具体到代码事实 - 基线未列出但实际发现 → 新增条目并标注
[+] added (来源)
基线触发线索按"sink 语义"分类(不按业务命名):
- 管理后台 / admin 端点:
/admin/*//manage/*//console/*//ops/*,应仅管理员可达 - 内部 API:
/internal/*//api/v1/internal/*//_api/*,意图仅内部服务调用 - 调试 / 开发遗留:
/debug/*//pprof/*//.env//actuator/*//.git/*//.DS_Store/ phpinfo - API 文档 / 内省:
/swagger.json//openapi.json//v3/api-docs/ GraphQL__schema内省 - 数据导出 / 报表 / 日志:
/export/*//report/*//logs/*,含批量数据 - 配置 / 健康检查暴露过多:
/health//status暴露版本号、内部地址、DB 连接 string、依赖列表 - 静态资源下的敏感文件:
/static/.env//uploads/backup.sql//public/config.yml - OPTIONS 预检 / CORS 旁路:预检响应里泄露的端点列表
- WebSocket / SSE 端点:仅前端隐藏入口,后端未做握手鉴权
- 代码模式:路由表里 protected 分组之外的"漏挂端点";handler 入口缺
auth.Required()/middleware.Auth()调用;静态文件服务挂载在含敏感文件的目录
思考检查点
加载本 skill 时按这些问题思考:
- 这个端点应该"谁可访问"?前端隐藏不等于后端鉴权——后端是否独立校验?
- 路由是否挂在 protected 分组下?handler 入口是否调了认证中间件?
- 静态资源 Server 的根目录里是否混入了
.env/backup.sql/ 配置文件? - "无凭证"和"空凭证"两种探测都做了吗?fail-open 缺陷常表现为"有头即放行"
- 同子系统其他敏感端点的鉴权是逐项配置的吗?需要按端点账本独立测
前置条件与安全边界
- 仅在授权环境执行验证,禁止越权改写生产数据。涉及删除/覆盖/不可逆写时,按
common/closure-verification.md的《破坏性 / 不可逆动作的闭环边界》执行——优先哨兵自证或非破坏差分,二者都做不到就停suspected,不得对真实业务数据执行破坏动作来强行闭环。 - 单接口默认最多 6 次请求(基线 2 次 + 对照 2 次 + 复验 2 次)。
- 单轮只改变"是否携带认证信息"一个变量,不联动改参数。
- 一旦形成 confirmed 证据,立即停止扩展探测。
检测步骤
Step 1:基线与端点画像
- 从端点账本(
recon-methodology产出的endpoint-ledger.jsonl)筛选"应受保护"端点(产品语义、文档、页面入口、业务字段含敏感数据) - 使用有效登录态发送 1~2 次基线请求,记录状态码、响应体关键字段、业务副作用
- 区分"业务端点"和"基础设施端点"(debug / actuator / swagger)——后者常被遗忘
Step 2:无凭证对照
完全删除全部认证信息(Cookie、Authorization、自定义 Token 头、Session ID)后重放同请求,对比是否仍返回敏感业务数据或执行成功。
Step 3:空凭证 / fail-open 探测
保留认证头但把其值置空(Authorization: 、空 Token、user_id= 空、uid=0、X-User-Id: 0),探测后端把"空身份"误判为可信/默认放行的 fail-open 缺陷——部分中间件"有头即放行、不校验值"。
Step 4:路径与方法变体
- 同一资源不同方法(GET / POST / PUT / OPTIONS / HEAD)鉴权严格度可能不一致
- 大小写 / 末尾斜杠 /
%2e编码绕过路由前缀匹配 - 同一端点不同 API 版本(
/v1vs/v2)鉴权配置可能漂移 - 对比有/空/无凭证三种结果,重点验证是否仍返回敏感业务数据
- 对可疑结论重复至少 1 轮复验,确认可稳定复现
示例库
正例形态(代码层根因)
router.GET("/admin/users", handlers.ListUsers)— admin 端点漏挂认证中间件(no-cred-admin-endpoint-missing-middleware-unauth)http.Handle("/debug/", http.DefaultServeMux)— 调试路由暴露到公网(no-cred-debug-route-exposed-unauth)if r.Header.Get("Authorization") != "" { /* trust */ }— 有头即放行(empty-token-header-fail-open-unauth)http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./private"))))— 静态目录混入敏感文件(no-cred-static-sensitive-file-served-unauth)
窄化反例(必须避免)
以下是未授权访问维度的典型窄化误判:
- "前端不显示该入口 → 后端必然有保护" — 错。前端隐藏不等于后端鉴权,直连 API 即可绕过前端
- "已测了 admin 路径 → 跳过其他敏感端点" — 错。每个端点的鉴权独立配置(中间件按路由分组 / 按 handler 调用),需按端点账本逐项测,不能用单点结论代表全站
- "看起来是 healthcheck → 应该是公开的" — 错。healthcheck 可能泄露内部地址、版本号、依赖列表、数据库连接 string、堆栈信息,需逐字段判定敏感度
- "已在某子系统命中未授权 → 其他子系统假定同样" — 错。跨子系统独立结账,不同子系统由不同团队 / 不同时期开发,鉴权命中率不可推广
- "返回 200 但内容是
{}→ 安全" — 错。需验证是否能从其他参数变体取到敏感数据(如改 GET 为 POST / 加分页参数 / 改 ID)
反例义务(必须遵守)
为什么这里是「必须」:反例义务属于交付契约——"未发现未授权访问"或"鉴权已生效"结论是覆盖完整性的产物声明,缺失反向验证清单会让下游误信"该维度全站安全"。
写"未发现未授权访问"或"全站鉴权已生效"前,产物必须包含:
- 测过的"应受保护"端点完整清单(按 sink 语义枚举:管理后台 / 内部 API / 调试遗留 / API 文档 / 数据导出 / 健康检查 / 静态敏感文件 / WebSocket 等全部触发线索类别,不按 URL 前缀筛选)
- 每个端点尝试的认证变体(有凭证基线、无凭证、空凭证、方法变体、路径编码变体、版本变体)
- 每个端点的对照证据(基线响应 / 无凭证响应 / 空凭证响应 / 关键敏感字段)
清单不完整 → 结论降级为 partial-coverage 并显式声明未覆盖范围(例如:仅测了业务 API、未测 debug / swagger / 静态资源敏感文件)。
闭环验证要求(必须遵守)
通用闭环口径见同根目录 common/closure-verification.md(技能表 path 列同一抽取根下,需要时 read_file 读取)。核心:结论须形成「输入 → 处理 → 真实危害 → 可复核证据」完整证据链;仅凭状态码、跳转、页面轮廓等中间信号最多判 suspected,证明无/空凭证下真实读到敏感数据或写操作回读生效才判 confirmed。
实际效果验证方向(至少证明一类)
- 无凭证读敏感数据:无凭证情况下读取到本应受保护的真实业务数据(含具体字段 / 文件内容)
- 无凭证执行写操作:无凭证情况下执行了本应受保护的写操作,并通过回读或状态变化证明生效。若该写为不可逆动作(删除/覆盖/批量改),回读证明改走哨兵自证或非破坏差分,不得对真实数据执行(见《破坏性 / 不可逆动作的闭环边界》)
- 若只有 200、跳转异常或页面轮廓,但未证明真实数据/能力可用,不能给
confirmed
判定标准
| 现象 | 判定 |
|---|---|
| 无凭证仍可读取敏感数据或执行受限操作 | confirmed |
| 行为异常(如 200 空壳响应、含轮廓但无字段)但未证明数据/能力可用 | suspected |
| 无凭证返回 401/403/登录跳转且无敏感数据泄露 | not vulnerable |
| 只测了部分类型端点(如仅业务 API),未覆盖 debug / swagger / 静态敏感文件 | partial-coverage(不得宣称 safe) |
不可逆动作例外:上表 confirmed 行涉及删除/覆盖/不可逆写时,按
common/closure-verification.md《破坏性 / 不可逆动作的闭环边界》——不得对真实业务数据执行,改走哨兵自证或非破坏差分,二者都做不到则降suspected。
修复建议
- 服务端强制执行统一鉴权中间件与资源级授权校验,禁止"漏挂端点"
- "公开路由"和"受保护路由"做显式分组(白名单公开端点 + 兜底拒绝),禁止隐式放行
- 调试 / 监控 / API 文档端点不上生产,或加独立鉴权与 IP 白名单
- 静态资源 Server 的根目录单独隔离,禁止混入
.env/ 备份 / 配置文件 - 关键写操作增加审计日志,便于回溯未授权调用
- 历史接口做回归测试,确保无凭证访问基线一致返回未授权