访问控制

场景:未受保护的管理员功能

image-20261001233821391

image-20261001233325730

这道比较简单,是**robots.txt的知识点。这个只是给爬虫看的协议,不能阻止人类访问。**这个漏洞没有在服务端校验访问页面的权限,只要拿到了这个路径,任何人都能对用户进行删除。

场景:无保护的管理员功能,且相关 URL 难以预测

image-20261003001659258

源码搜索发现admin路径。

场景:用户角色由请求参数控制

image-20261004002117344

仍然是很熟悉很简单的一道题。最弱的前端鉴权,cookie参数可以被前端修改,服务端完全信任客户端 Cookie。如果是防护更完善的网站,每次响应都会重新下发 Set-Cookie 来覆盖修改,就不能在浏览器 Application 里改了,要用 Burp 抓包,直接修改请求包里的 Cookie再放行,每次请求都手动改成 true,这样就不会被服务器响应覆盖。

场景:用户角色可以在用户个人资料中修改

image-20261005202851270

image-20261005202933592

原理:垂直越权。在修改个人资料的接口这里,会接受roleid的角色参数,但服务端不校验是否有权限修改自己的角色。普通用户只要在更新资料的请求里加上roleid=2,就能给自己提权成管理员。

后端更新用户资料时,没有对传入字段做白名单过滤,也没有校验「当前用户是否有权限修改该字段」

实战的时候怎么确认可以修改的字段名?

看正常响应返回的字段名。

① 优先查「个人信息查询接口」的响应(90% 命中率)

角色字段的正确来源:普通用户就能调用的「个人信息查询接口」

一个非常重要的实战思路:永远不要去权限终点找线索,要去普通用户可及的接口找。

后台页面是 “门”,钥匙不会贴在门上;用户信息接口才是 “配钥匙的地方”。

先调用获取用户资料的接口(一般是 GET /my-account、/user/info),把返回的所有字段列出来。
凡是和角色、权限、等级相关的,都是候选:
role、roleId、role_id、roleid、level、userLevel、is_admin、isAdmin、admin、type、userType、privilege
测试铁则:后端返回给你的所有字段,都可以尝试往更新接口里传,看能不能改。

② 看前端 JS 逻辑

F12 全局搜索 admin、role、level,找类似 if (user.role === ‘admin’) 的判断,直接拿到字段名和对应的值。

什么时候能搜到修改字段?

前端是 SPA 单页应用(Vue / React / Angular)的时候,命中率极高。 因为这类应用的路由守卫、菜单显隐、页面权限控制都是在前端 JS 里做的,代码里一定会有类似:

1
2
3
if (user.roleId === 2) {
showAdminMenu = true
}

这种情况下 F12 全局搜 admin、role,能直接拿到:

  • 准确的字段名(是 roleId 还是 role_id 还是 isAdmin)
  • 准确的管理员取值(是数字 2 还是字符串 admin)
什么时候搜不到?

服务端渲染(SSR)页面,也就是这道题这种,搜不到是正常的。 因为权限判断全在后端做完了,前端拿到的就是最终渲染好的 HTML,JS 里根本没有权限判断逻辑。去搜当然什么都没有。

有些站点会把角色存在 Cookie 里,比如 role=user,可以直接尝试修改。

④ 字典枚举

以上都没有的话,用上面列的常见权限字段名,一个个往更新请求里加了试。

怎么确定管理员的取值?

按优先级试,基本不会超出这个范围:
数字型:普通用户是 1 → 依次试 0、2、99、100
很多系统 0 是最高权限,1 是普通用户
也很常见 1=普通用户、2=管理员、3=超级管理员
字符串型:依次试 admin、administrator、root、super

==如果存在水平越权(IDOR),可以先看其他用户的信息,直接拿到管理员账号的 roleid 是多少,精准修改。==

场景:用户 ID 由请求参数决定【附带操作型IDOR】

image-20261005214603728

这道题有点搞笑,我还给想难了,最简单的做法就是提示里这个。

我当时做的时候,先看正常接口返回,当时bp抓包看返回字段里有个username,直接通过邮件更新这个接口,给表单末尾加上了&username=calos 直接把我这个wiener的用户名给改了【实则这里并非如此,见后文】,然后进?id=carlos这里查看题目需要的apikey

image-20261005215309171

但是我灵机一动,转回去看?id=wiener

image-20261005215349690

好神奇,居然能同时看两者的apikey。

然后我等这个容器过期之后又重新去尝试了一下题目给的最简单的做法。能直接看。然后整个复盘了一下全过程。发现中间的都是多余操作hhh,我修改邮箱接口这里,修改的还是wiener的。传入的username参数被忽略了。当然这种从A的接口修改B的越权思路是可行的,在实战中也是高发的漏洞。只是单纯这里的接口不接收username。

简单说:这道题的 IDOR只存在于读接口,不存在于写接口。不是所有接口都接受用户标识参数,也不是所有接口都有同样的漏洞。我第一次尝试的时候失败单纯是因为浏览器缓存问题。

实战中,不是把自己的用户名改成 B,自己就变成 B」
而是「你还是用户 A,但你传 B 的用户 ID,就能读 / 改 B 的数据」

实战典型场景

1、修改个人资料接口

请求体里有user_id/uid参数,把它改成别人的 ID,就能修改别人的昵称、邮箱、手机号,甚至重置密码。

2、删除接口

POST /delete-address?id=123,把地址 ID 改成别人的,就能删掉别人的收货地址。

3、订单 / 工单查询接口

GET /order?order_no=20240001,改订单号就能看别人的订单信息。

4、关键特征

后端代码的通病都是同一句话:
只校验「你有没有登录」,不校验「这个数据是不是你的」。
客户端传什么对象 ID,就直接操作什么对象。

怎么快速判断一个接口接不接受用户 ID 参数?

这是实战 IDOR 测试的标准流程,不用瞎猜:

步骤 1:先找基线

正常操作一次,抓包看:

  • 请求里有哪些和用户 / 对象相关的参数
  • 响应里返回了哪些字段(比如user_id、uid、username)

步骤 2:候选参数往里加

把响应里出现的用户标识字段,挨个加到请求里试:

  • URL 参数:?uid=xxx、?user_id=xxx
  • 请求体参数:&uid=xxx、"user_id":"xxx"

步骤 3:验证效果

  • 读接口:看返回的数据是不是变成了目标用户的
  • 写接口:改完之后,用目标用户账号登录(或者用读接口查),看数据有没有真的被改掉

image-20261005224436890

这里返回的就是wiener的。

步骤 4:排除假阳性

如果加了参数没反应,就说明这个接口不接受客户端指定目标用户,只认 session,就像这道题的修改邮箱接口一样,直接换下一个接口测。

场景:用户 ID 由请求参数决定且具有不可预测性

image-20261005225150032

image-20261005225254507

漏洞原理:很多开发者以为「用 GUID/UUID 代替自增 ID,别人猜不到就安全了」,但这是典型的模糊安全误区。==只要用户标识在公开页面泄露,并且后端不校验数据归属,一样存在 IDOR。==真正的安全问题从来不是「ID 能不能猜到」,而是: 后端收到 ID 参数后,有没有校验「这个 ID 对应的数据,是不是属于当前登录用户」。

进主页之后找到carlos发的博客,然后url里面得到他的guid。再进my-account?id=a7bb84e0-9b5d-4af8-8fec-8584b0c17ce6就能得到他的信息。

这类 IDOR 的测试思路:

  1. 先找任意一个公开场景,拿到目标用户的标识(不管是数字还是 GUID)
  2. 把这个标识代入到查询 / 修改接口里
  3. 看能不能返回 / 修改目标用户的数据
  4. 防坑:去爆破 GUID,完全没必要,也几乎不可能,GUID 一定是在某个公开地方能拿到的。找错地方:不要在个人页面找,去博客、评论、社区这类有用户公开内容的地方找

场景:用户 ID 由请求参数控制,重定向过程数据泄露

image-20261006125610606

漏洞原理:后端逻辑顺序错误:先查询并渲染好目标用户的完整数据,再判断权限并返回 302 重定向。浏览器会自动跳转所以肉眼看不到,但 302 响应的响应体里已经完整包含了目标用户的敏感信息。

解法:在bp抓包界面,把请求参数的id改成目标carlos。

这道题和前面的用户id有请求参数决定在表现上有相似之处,但是。那道题是后端完全没有做权限检验,这道题是做了权限检验,但检验的代码执行顺序弄反了,导致做了也白做。这里是先渲染。

==做越权测试必须用 Burp 看原始 HTTP 响应,绝对不能靠浏览器页面的表现来判断有没有漏洞。==

通用测试方法

遇到任何越权场景,按这个步骤判断:

  1. 传入越权参数,看返回状态码
  2. 如果是 302,必须下拉看响应体,绝对不能只看状态码就跳过
  3. 响应体有完整目标数据 → 先渲染后校验,存在数据泄露
  4. 响应体为空 / 只有提示文字 → 先校验后渲染,控制有效

场景:用户 ID 由请求参数决定 + 密码泄露

image-20261006233617931

这里可以1看到密码是已经出现在界面上,只是用圆点遮挡了的。

image-20261006233753831

明文出现在这里。

这道题是一个漏洞利用链条:利用前面的,用户id由请求参数控制。然后可以通过这个进管理员这里看见管理员账号密码。

这里的原本的想法是既然已经进管理员界面了,那我直接去删除carlos这个账号不就行了,然后我这里就想着关掉浏览器代理去删但是没成功,仍然是wiener的界面。

查了一下:==读接口的 IDOR 漏洞,不代表写 / 操作接口也有同样的漏洞。==这个真的是非常重要,每个接口都是需要单独测试的,权限和漏洞不一样,我前面记笔记还写过,这里给忘了。

这里两个接口的权限校验完全不同

1. 查看个人页面(读接口:GET /my-account?id=xxx)

后端逻辑:

  • 只校验「你有没有登录」
  • 不校验「这个 id 是不是你的」
  • 所以你传管理员的 id,就能越权看到他的页面和密码

这是读权限的越权,只能看,不能做操作。

2. 删除用户(管理操作:POST /admin/delete)

后端逻辑:

  • 先校验「你当前登录的账号角色是不是管理员」
  • 不是管理员 → 直接拒绝,根本不执行删除
  • 和你传什么 id 参数没关系

这是写 / 管理权限,有严格的角色校验,普通用户 wiener 就算知道接口地址,也执行不了删除

这里的漏洞链式利用:

  1. 利用读接口的 IDOR + 前端密码泄露 → 拿到管理员的明文密码
  2. 用密码登录管理员账号 → 获得真正的管理员角色权限
  3. 进入管理面板执行删除操作

为什么改回系统代理,页面还是 wiener?

因为登录身份和代理工具完全是两回事。
Burp 代理的作用:中间人抓包,它只是在浏览器和服务器之间转发请求,不改变、不决定你的登录状态。
登录身份存在哪:浏览器的 Cookie(Session)里。你登录 wiener 账号后,服务器给你发的 session cookie 存在浏览器本地。
所以:
开 Burp 代理 → 浏览器发的请求经过 Burp 转发,身份还是 wiener
关 Burp、改回系统代理 → 浏览器直接发请求,cookie 还在,身份还是 wiener
你没有换账号登录,身份就不会变,和代理开不开没有任何关系。这不是操作错误,是正常现象。

补充:实战里的通用规律,读、写、管理三类接口的权限校验,通常是完全独立的

  • 能越权读别人数据,不代表能越权改别人数据
  • 能越权改别人数据,不代表能越权删别人数据
  • 能越权操作用户数据,不代表能进管理后台

==每一个功能、每一个接口,都要单独测试权限。不能因为一个接口有越权,就默认所有接口都有越权。==

读接口有漏洞 → 泄露高权限凭证 → 提升权限 → 执行高权限操作,这是非常经典的实战利用路径。

场景:不安全的直接对象引用(文件型 IDOR)

image-20261007002958018

点击浏览下载。把下载url改成1.txt就可以看到前面的聊天记录了。泄露密码。【小技巧,右键点击下载的文件可以复制下载url】

https://0a5f00960384a67e804e7b5100bd00b0.web-security-academy.net/download-transcript/1.txt

image-20261007002131099

这里会直接跳转下载链接。

获得carlos的密码然后登录。

1. 核心本质:IDOR 是一类漏洞,不是一个特定的点

之前做的改?id=wiener、改 GUID,都属于数据型 IDOR,操作的是数据库里的用户数据;这道题是文件型 IDOR,操作的是服务器上的静态文件。

但底层逻辑完全一致:

  • 对象的唯一标识(用户 ID / 文件名)完全由客户端控制
  • 后端只负责 “根据标识返回对应内容”,完全不校验「这个内容的归属权」「当前用户有没有权限访问」

PortSwigger 设计这道题的目的,就是打破 “IDOR 就是改 URL 里的用户 id” 的刻板认知 ——任何客户端可控的 “对象引用标识”,只要没做权限校验,都是 IDOR。

2. 戳破一个最普遍的开发安全误区

这道题精准模拟了实战里极其常见的错误认知:

「静态文件 / 资源文件不需要做权限控制,只要不对外公布路径,别人就找不到」

两个典型的错误逻辑:

  • 误区 1:动态接口要鉴权,静态文件(txt、pdf、图片、附件)不用鉴权
  • 误区 2:用自增数字当文件名,只要不主动遍历就不会泄露

但实际上:

  • 只要文件路径有规律(数字递增、命名有迹可循),就可以被枚举
  • 只要后端不做归属校验,知道路径就能直接拿,和登不登录、是不是本人的文件都没关系

这和之前 “GUID 不可预测就安全” 的误区是同一个核心:安全不能靠 “别人猜不到”,必须靠主动的权限校验。

3. 训练测试敏感度:下载接口也是 IDOR 重灾区

很多新手测越权只会盯着页面接口、数据接口,会天然忽略 “下载 / 查看附件” 这种功能。 这道题就是在强化测试直觉:

  • 只要看到 URL 里有/xxx/数字.后缀这种格式(/download/123.pdf、/attachment/456.jpg),条件反射就要测 IDOR
  • 浏览器触发下载、看起来很 “正常” 的功能,恰恰容易藏越权漏洞
  • 文件里的敏感信息(密码、身份证、银行卡、订单信息),往往比接口数据更直接、危害更大

场景:基于 URL 的访问控制机制绕过

漏洞类型:访问控制绕过(前端网关权限绕过)

核心原理:架构分层导致的权限脱节 ——前端反向代理 / 网关只根据请求行的 URL 拦截 /admin 路径,但后端应用支持X-Original-URL协议,会以这个请求头里的路径作为真实路由。我们请求行走公开的根路径/骗前端放行,偷偷在头里指定真实路径/admin,就能绕过拦截访问管理后台。 目标:绕过前端拦截 → 进入管理员面板 → 删除用户carlos

一、网关(前端代理)的作用

  1. 统一入口:所有用户的请求都先到这里,再转发给后面的各个业务服务器
  2. 安全拦截:黑名单路径、恶意请求、非法 IP,都在这一层直接拦掉,不用到后端
  3. 负载均衡:把请求分给不同的后端服务器
  4. 路径改写:比如用户访问 /api/xxx,网关改成 /internal/xxx 再转发给后端

二、权限控制的常见分工

为了省事,很多团队会这么设计:

  • 网关层:做粗粒度的路径拦截 比如:所有 /admin 开头的路径,普通用户一律拦住,只有管理员 IP 能过。 它只管「路径能不能进」,不管具体业务逻辑。
  • 后端层:做细粒度的权限校验 比如:这个管理员能不能删用户、能不能改配置。

✅ 正常情况下是没问题的:网关把非管理员的/admin请求全拦了,后端只需要处理已经进来的管理员请求。

三、X-Original-URL 本来是干嘛的?

它根本不是为了搞漏洞而生的,它是一个正经的标准协议头。

它的初衷

网关经常会做路径改写。举个例子:

  • 用户浏览器请求的是:GET /api/v1/user
  • 网关转发给后端的时候,改成了:GET /internal_service/user

后端收到请求的时候,请求行里的路径已经被改掉了。但后端有时候需要知道「用户原本访问的是什么路径」,用来打日志、做统计、兼容旧版本。

于是就有了 X-Original-URL 这个约定:

网关在转发请求的时候,把用户原始的请求路径,放在 X-Original-URL 请求头里,一起发给后端。 后端如果需要,就可以从这个头里拿到用户真实访问的原始路径。

这是一个非常正常、非常常用的技术设计,本身完全没有问题。

四、漏洞是怎么产生的?—— 两层脱节

问题出在:网关做权限校验的依据,和后端做路由的依据,不是同一个东西。

这道题的两层逻辑

第一层:网关(门卫)

它做权限校验的时候,只看请求行里的 URL 路径。

  • 请求行是 GET /admin → 敏感路径,直接拦截,不给进
  • 请求行是 GET / → 公开首页,放行

它根本不看、也不知道还有个 X-Original-URL 头。

第二层:后端应用

它做路由的时候,优先读取 X-Original-URL 头里的路径,把它当成真实要访问的路径。

  • 有这个头 → 按头里的路径走
  • 没有这个头 → 才按请求行里的路径走

==权限校验在网关,用的是请求行 URL;实际执行业务在后端,用的是头里的 URL。两者基准不一样,就被绕过了。==

这不是某一行代码写错了,是架构分层之后,两层的权限基准没有对齐,属于典型的架构型漏洞。

五、为什么后端会支持这种头?开发故意留的?

绝大多数情况不是开发故意写的,而是Web 框架 / 中间件默认就支持,很多开发甚至都不知道自己的后端会读这个头。

==比如:==

  • ==Apache、Nginx 的一些模块默认支持==
  • ==Spring Boot、Django 等框架的路由组件,有兼容 X-Original-URL 的配置==
  • ==很多反向代理、API 网关默认就会带上这个头==

开发的心态通常是: 「网关已经把 /admin 拦住了,普通用户根本到不了后端,我后端不用再校验一遍了。」 他根本没意识到,用户可以自己加这个头,骗网关放行,让后端执行管理路径。

五、同类的绕过思路还有哪些?

这是一个大类:访问控制绕过之「校验字段与执行字段不一致」。 X-Original-URL 只是其中一种,实战里还有很多同逻辑的变种:

1. 其他 URL 重写头

遇到网关拦路径的时候,按优先级挨个试:

  • X-Original-URL
  • X-Rewrite-URL
  • X-Forwarded-URI
  • X-Forwarded-URL

逻辑完全一样:请求行走公开路径,头里藏真实路径。

2. IP 限制绕过

如果网关限制「只有内网 IP 才能访问 /admin」,它校验的是 X-Forwarded-For 头,那你就可以自己加:

1
X-Forwarded-For: 127.0.0.1

骗网关你是内网来的。

3. Host 头绕过

如果权限是绑定域名的,比如只有 shturl.cc/U5H 才能进后台,网关校验的是 Host 头,那你就可以:

  • 请求行访问 GET /admin
  • Host 头写成普通域名 shturl.cc/u
  • 或者反过来,请求行走普通路径,Host 头写成管理域名

六、实战里怎么测这类漏洞?

非常标准的测试流程:

  1. 访问目标敏感路径(比如 /admin),返回 403 / 拦截页面,确定是网关 / 代理拦的
  2. 把请求行改成公开路径(比如 /、/index.html)
  3. 加上各种 URL 重写头,值填敏感路径 /admin
  4. 发请求,看响应里有没有出现管理页面的内容

怎么知道敏感路径的存在与否?

这里其实还是信息收集的步骤。

第一优先级:被动收集

通过标配文件、前端JS、页面隐藏线索、公开渠道泄露等方式找敏感路径。

1. 标配文件:直接送答案的地方

这是每个网站理论上都有的文件,也是第一个必看的,90% 的新手都会跳过。

表格

文件 作用 典型内容
robots.txt 告诉搜索引擎哪些路径不要爬 Disallow: /admin Disallow: /manage 直接把敏感路径列给你
sitemap.xml 网站地图,列所有公开路径 经常会混入管理、内部页面的路径
/.well-known/security.txt 安全说明文件 经常会泄露后台、管理邮箱等信息

直接在域名后面加路径访问就行:

1
2
https://example.com/robots.txt
https://example.com/sitemap.xml

这道靶场题的 /admin,在真实网站里大概率就写在 robots.txt 的 Disallow 里。

2. 前端 JS:最大的路径泄露源

现在前后端分离的网站,所有路由路径、接口路径全写在打包的 JS 文件里。前端只是根据你的角色隐藏菜单,但路径本身全部都在代码里。

怎么找
  1. 打开浏览器开发者工具 → 「网络」标签 → 筛选 JS
  2. 打开体积最大的那个打包 JS 文件
  3. 搜索关键词:admin、manage、dashboard、/api/、route

经常能直接搜出完整的路由表:

1
2
{ path: '/admin', component: AdminPanel },
{ path: '/admin/delete', component: DeleteUser },

前端菜单不给你显示,但路径全在代码里躺着。

3. 页面里的隐藏线索
  • HTML 注释:开发经常在源码里注释掉管理入口,<!-- <a href="/admin">管理入口</a> -->
  • 404 / 报错页面:很多网站的 404 页面会泄露网站框架、默认管理路径
  • 页脚 / 帮助文档:经常会有「管理登录」「商户后台」之类的入口链接,只是藏得深
  • Cookie / 响应头:很多响应头里会带路径信息,比如 Location: /admin/login
4. 公开渠道的泄露
  • GitHub/Gitee:搜目标域名,经常能搜到内部文档、部署脚本,里面写满了管理路径
  • 招聘信息:技术岗 JD 里经常会写「使用 XX 管理后台」,直接暴露路径名
  • 历史快照:Wayback Machine(网页时光机)里能找到网站曾经存在过的路径

这里我无聊顺手拿京东做了一下实验。这种大厂的防御策略很严格,直接访问主站的\robots.txt是没用的,bp抓包之后useragent改成搜索引擎的字段也不行,尝试了很多次都是503。直接进网站地图也不行,网站地图也是需要搜索引擎的身份的。这个不是我最近的重点所以没去接着尝试。先跳过了,不过也算积累了一点经验,比如target要改,http支持的版本不一样也容易被503,还有就是多余的信息,容易被认出来是个人用户,然后就是他们可能会只允许搜索引擎的ip段进这些路径。不过确实在前端js里面搜索出来一些路径。不过大厂好像也无所谓就是了,你知道也打不进去hhhh

第二优先级:精准字典爆破

被动收集找不到的时候,才用字典扫。绝对不是字典越大越好,精准小字典效率是大字典的 10 倍。

1. 什么时候才爆破?
  • 被动收集完了,确实没找到
  • 目标是 CMS / 框架(比如 WordPress、Spring Boot),有固定的默认路径
  • 有明确的命名规律,可以生成自定义字典
2. 用什么字典?

推荐从 SecLists 这个标准字典库里选,按场景用小字典,别用几万行的大字典:

  • 通用后台路径:Admin-panels.txt(几百行,都是常见管理后台路径)
  • 通用目录:common.txt(几千行,最常用的路径)
  • 特定 CMS:对应 CMS 的专用字典(比如 WordPress、Drupal)

实战真理:1000 行的精准字典,比 10 万行的大字典有用得多。大字典大部分都是无效路径,慢、容易触发 WAF 封 IP,还扫不到东西。

3. 用什么工具扫?

表格

工具 场景 特点
dirsearch 入门首选 Python 写的,简单直接,自动识别状态码、长度
ffuf / gobuster 高速爆破 速度极快,适合大目标
Burp Intruder 精准验证 适合小字典、需要带 Cookie/Header 的场景

你问的「放 BP 里面加字典吗」:Burp 的 Intruder 模块可以做目录爆破,但专门的目录扫描工具效率更高。Burp 更适合找到路径之后,做验证和绕过测试。

4. 爆破的核心技巧
  • 看长度,不只看状态码:很多网站统一返回 404 状态码,但敏感路径的响应长度明显不一样
  • 处理重定向:302 跳登录页很正常,路径本身是存在的,只是需要登录
  • 控制速率:别开最快,容易被 WAF 封

识别特征

如果拦截页面非常简洁、只有一句话、样式统一,大概率是网关 / WAF 拦的,这种场景非常适合试这类绕过。 如果是后端返回的精致的 403 页面、带登录跳转,那大概率是后端层的权限,这类头就不好使了。

核心:只要访问控制的校验点,和实际业务的执行点,不是用同一个字段做判断,就一定存在绕过的可能。

==校验什么,就给它看安全值;执行什么,就偷偷给后端传真实值。==

完整链路:

image-20261011205251182

扒敏感路径,404跳过403、503、302注意,判断哪一层拦截的,绕过。

payload写法:

回到这道题。发送的请求为:

1
2
GET /?username=carlos HTTP/1.1
X-Original-URL: /admin/delete

路径 藏在 X-Original-URL 头里 → 用来绕网关的路径拦截
参数 放在请求行里 → 保证后端一定能正常读到

【不是不能把参数写在头里,是这么写兼容性最差、很容易失效,这道靶场题的后端实现也不支持这么写。】

第一层:前端网关(拦截的那层)

它的拦截规则是只看「请求行里问号前面的路径部分」:

  • 路径是 /admin/... → 敏感路径,直接拦截
  • 路径是 / → 公开首页,放行

它不校验问号后面的查询参数,也根本不读 X-Original-URL 这个头。

所以:

  • ❌ GET /admin/delete?username=carlos → 路径就是 /admin/delete,直接被拦
  • ✅ GET /?username=carlos → 路径是 /,参数带在后面不影响,网关直接放行

第二层:后端应用(执行业务的那层)

它的路由逻辑是:优先读 X-Original-URL 头里的内容当路径,但查询参数默认还是从「原始请求行」里取。

这是最关键的一点: 绝大多数 Web 框架对 X-Original-URL 的标准实现,都只用来重写路径(path),不会去解析这个头里的 ?key=value 参数。参数本来就在请求行里有一份,后端直接读原始请求的参数就行。

如果强行写成:

1
X-Original-URL: /admin/delete?username=carlos

很大概率会出现两种结果:

  1. 后端把整个字符串当成路径,找不到对应页面,返回 404
  2. 后端只提取了路径部分 /admin/delete,里面的参数被直接忽略,删除操作因为缺少目标而失败

X-Original-URL 的设计初衷:网关做了路径改写,用户原本访问的是 /api/user,网关改成 /internal/user 转发给后端。后端想知道用户原本访问的路径是什么,就从 X-Original-URL 里拿。它设计出来就是只传路径的,查询参数在原始请求里本来就完整存在,不需要在头里再传一遍。所以主流的 Nginx、Spring Boot、Django 等组件,对这个头的默认处理都是:
只替换请求的路径部分
查询参数、请求体、Cookie 这些,全部沿用原始请求的内容

场景:基于方法的访问控制措施是可以被绕过的

直接改session,在普通账户下进不去。

image-20261012163907702

修改请求类型。

image-20261012164440057

执行成功之后跳回admin管理面板界面。

这里修改payload涉及到get请求和post请求的区别。

怎么判断特征?典型触发场景:

在测试一个接口的时候,出现以下任意一种现象,就该立刻想到「试 HTTP 方法绕过」:

  1. POST 请求返回 401/403 未授权,但路径、参数、Cookie 都没问题,感觉 “本该有权限,只是被拦住了”
  2. 返回 405 Method Not Allowed(方法不允许),明确告诉你这个方法不行
  3. 同一路径,GET 能访问看数据,POST 提交操作就被拦
  4. 网关 / WAF 提示「非法请求」,但参数、内容都正常

底层规律

只要观察到:权限拦截和 HTTP 方法强绑定—— 比如 “只有 POST 才拦截,GET 就没事”,就一定有方法绕过的空间。
本质还是那个通用逻辑:权限层校验方法,业务层兼容多方法,两层标准不一致。

方法访问控制实战标准测试顺序(按命中率从高到低)

不要上来就瞎改冷门方法,按这个顺序试,90% 的场景前两步就能出结果。

第 0 步:先打基线

先拿到正常的原始请求,确认:

  • 完整的参数列表、参数名、参数格式
  • 原始方法、原始返回结果
  • 确保不是参数错、Cookie 错导致的拦截

第 1 优先级:POST → GET(命中率最高,约 60%)

这是最通用、最容易命中的改法,也是你这道题的标准解法。

操作步骤

  1. 请求行的 POST 改成 GET
  2. 把请求体(body)里的所有参数,原封不动移到 URL 后面,用 ? 拼接,参数之间用 & 连接
  3. 删除 Content-Type、Content-Length 这两个请求头(GET 请求没有请求体,这两个头没用了)
  4. 发送请求

示例

原始 POST:

1
2
3
4
POST /admin-roles HTTP/2
Content-Type: application/x-www-form-urlencoded

username=wiener&action=upgrade

改成 GET:

1
GET /admin-roles?username=wiener&action=upgrade HTTP/2

为什么有效

  • 权限层:规则只写了「拦截 POST /admin-roles」,GET 不在黑名单里,直接放行
  • 后端:绝大多数 Web 框架的接口,默认同时支持 GET 和 POST 传参,参数对就执行

第 2 优先级:X-HTTP-Method-Override 头(企业级命中率第二,约 25%)

这是实战里比冷门方法有用得多的技巧,绝大多数中大型系统、微服务架构都支持这个协议头,很多新手不知道。

原理

专门为「网关 / 防火墙只允许特定方法」的场景设计的协议:

  • 外层请求用 POST(网关允许的方法),正常放行
  • 加一个 X-HTTP-Method-Override 头,告诉后端「实际按这个方法执行」
  • 后端读取这个头,把请求当成对应的方法处理

操作步骤

  1. 请求行保持 POST 不动(保证网关放行)

  2. 在请求头里加一行:

    1
    X-HTTP-Method-Override: PUT

    (后面的方法改成你想要的,比如 DELETE、PUT、PATCH)

  3. 请求体、参数都保持不动

  4. 发送请求

示例

1
2
3
4
5
POST /admin/user HTTP/2
X-HTTP-Method-Override: DELETE
Content-Type: application/x-www-form-urlencoded

username=carlos
  • 网关看:POST 请求,正常放行
  • 后端看:有覆盖头,按 DELETE 方法执行删除

同类扩展头

遇到不支持上面那个的,按优先级试:

  • X-HTTP-Method
  • X-Method-Override
  • X-HTTP-Method-Override

第 3 优先级:冷门 / 自定义方法名(兜底方案,约 10%)

原理

  • 权限层:只认识 GET/POST/PUT/DELETE 这些标准方法,对陌生方法名不做拦截规则,直接放行
  • 后端:很多框架遇到不认识的方法,会 fallback 成 POST 逻辑处理,只要参数对就执行业务

操作步骤

  1. 请求行的 POST 改成一个随便造的方法名,比如 POSTX、FOO、ABC
  2. 请求体、参数、头都保持不动
  3. 发送请求

示例

1
2
3
4
POSTX /admin-roles HTTP/2
Content-Type: application/x-www-form-urlencoded

username=wiener&action=upgrade

第 4 优先级:其他标准方法(约 5%)

按顺序试:HEAD → PUT → PATCH → OPTIONS

  • HEAD:很多权限系统不拦截 HEAD 请求,后端会返回和 GET 一样的响应体
  • PUT/PATCH:部分更新类接口本来就支持,只是权限层没加对应规则

快速判断是否绕过成功

不用等完整页面渲染,看这几个信号就知道成没成:

  1. 状态码变化:从 401/403/405 → 变成 200 / 302
  2. 响应长度变化:从几十字节的错误页 → 变成几千字节的正常页面
  3. 关键字出现:响应体里出现了 admin、success、升级成功、用户列表 等敏感内容
  4. 重定向目标:302 跳转到管理页面、操作成功页面(就是这道题现在的情况)

注意:302 重定向绝大多数时候是操作成功的标志,不是失败。后端操作完数据后,通常都会重定向回列表页,和正常网页操作完跳页是一个道理。

以后遇到任何权限拦截,先拆两个问题:

  1. 它在拦什么? 权限层的校验依据是什么?是路径?方法?IP?还是域名?
  2. 它在执行什么? 后端真正执行业务的时候,依据的是哪个字段?是请求头?参数?还是转发头?

==绕过公式:给校验层看它认识的、安全的值;把真实的操作,藏在它不校验、但业务层会读的地方。==

场景:多步骤流程型越权

这是业务逻辑类权限漏洞的经典代表,核心就一句话:
一个操作拆成多个步骤,权限校验只放在了前面的入口步骤,真正执行操作的最后一步,只校验参数、不校验权限。

普通账户之间访问无权限。这里的手法类似之前,进管理员账户抓包偷请求,再改参数替换成普通用户的wiener。

image-20261012221410491

这里有个小坑。

image-20261012221826276

业务逻辑里面这里是分了两步来提权的,先是点击提权,后面还有一层确认。前面这层是校验身份的。但后面那层确认,才是真正执行提权这个动作的步骤。并且没用鉴定身份。

image-20261012222146588

实战里要完成这样的操作,需要拿到「执行接口的地址 + 参数格式」。这个需要一点小技巧。

实战中拿到执行接口的常见方式(按概率排序)

1. 前端 JS 直接扒(最高发)

前后端分离的网站,所有接口路径、参数格式全在打包 JS 里。哪怕普通用户看不到管理按钮,接口地址全写在代码里。 比如搜 upgrade、promote、role 这类关键词,直接就能找到 /admin/upgrade 接口和参数格式,根本不用进管理面板。

2. 命名规律反推

开发起名都是固定套路,看到第一步就能猜出第二步:

  • 确认页接口:GET /admin/upgrade-confirm
  • 提交执行接口:POST /admin/upgrade-submit

只要在公开页面、低权限页面看到其中一步,就能反推出真正执行操作的接口。

3. 低权限接口复用

很多系统普通用户也有同类操作的接口,只是参数里有权限 / 范围限制。 比如普通用户可以升级自己的会员,接口是 /user/upgrade?level=vip,你把参数改成 level=admin,后端只校验参数格式,就直接升成管理员了。

4. 信息泄露带出

通过 IDOR、日志泄露、公开文档等其他漏洞,能看到管理员的操作记录、接口调用日志,直接带出完整的执行接口和参数。

==核心:业务流程的每一步,都要单独拿出来测权限。不能因为第一步有权限校验,就默认后面的步骤也有权限校验。==

多步流程的标准测试流程

按优先级从高到低:

第一步:先找执行接口

  • 扒前端 JS、搜关键词(submit、confirm、do、exec、delete、update)
  • 按命名规律反推执行接口路径
  • 目标:拿到「执行接口地址 + 参数格式」

第二步:直接测执行接口的权限

  • 用普通用户身份,直接构造执行请求发过去
  • 看返回:成功执行 = 漏洞;返回 401/403 = 有权限校验

第三步:如果执行接口有权限,再倒推测绕过

  • 试试方法绕过(POST 改 GET)
  • 试试路径绕过(X-Original-URL)
  • 试试参数篡改、越权操作目标数据

第四步:只有完全拿不到接口的时候,才走完整流程抓包

  • 高权限走流程 → 抓执行请求 → 低权限重放验证

场景:Referer 头绕过

image-20261012235245014

还是跟之前类似的步骤,登录管理员,拿到正常请求的完整格式,换session之后重放。

对比可以看到普通用户是没有referer的

image-20261012235440119

Referer 是 HTTP 标准请求头,浏览器会自动带上,用来表示「当前请求是从哪个页面跳转过来的」。
很多系统会用 Referer 做来源访问控制:默认只有从管理页面内部点击发起的请求,才是合法的管理员操作。

漏洞核心:

权限校验层:只检查 Referer 头是不是管理后台的地址,不是就直接拒绝
业务执行层:只要参数正确就执行操作,不二次校验身份
而 Referer 头是客户端完全可以自由伪造、修改的,我们手动把它改成管理页面地址,就能骗过校验

开发的典型误区:
「用户只能从管理页面点按钮发起请求,Referer 一定是 admin 页面;Referer 不对的肯定是非法请求。」
他默认了「用户不会自己构造请求、不会改头」,把浏览器的自动行为当成了可靠的安全依据。

完全正确——没有一眼就能识别的标志,都是通过「现象怀疑 → 控制变量验证」的流程确认的,但有非常典型的触发信号,遇到了就优先测 Referer,命中率很高。


一、实战里怎么识别是 Referer 校验?

1. 先找「怀疑信号」:遇到这几种现象,优先测 Referer

这是最关键的一步,先有怀疑的理由,再去验证,不用瞎猜。

最强信号(90% 概率)

同样的接口、同样的 Cookie 和参数,从页面里点按钮就能成功,直接在地址栏输入访问就被拒绝。

原理:

  • 从页面里点按钮:浏览器会自动带上当前页面的地址作为 Referer → 校验通过
  • 直接地址栏输入:Referer 是空的,或者是别的页面 → 校验失败

只要出现「页面点就好使,直接访问就不行」,第一反应就应该是 Referer 校验。

辅助信号

  • 报错提示里出现:非法来源、请从官方页面访问、来源无效、跨站请求被拒绝 这类文字,基本实锤
  • 所有参数、Cookie、方法都对,但就是返回 403/未授权,且不是路径拦截、不是方法拦截
  • 同一路径 GET 能看页面,POST 提交操作就被拦

2. 精准验证:控制变量法(100% 确认)

怀疑之后,用 Burp 做一次控制变量测试,就能板上钉钉:

  1. 先拿到被拦截的请求,Cookie、参数、方法、Host 所有东西都别动
  2. 只加一行请求头,填上你推测的合法 Referer(比如管理页地址)
  3. 发送请求
    • 从不通过 → 变成通过 = 100% 就是 Referer 校验
    • 还是拦截 = 和 Referer 没关系,换别的方向测

3. 和其他拦截的区分(避免认错)

拦截类型 核心区别
Referer 校验拦截 来源对就过,来源不对就拦;参数身份都没问题
普通权限拦截 不管你从哪来都拦;身份/权限不够
CSRF Token 拦截 校验的是请求体里的 token 参数,不是请求头里的地址
方法拦截 换方法就过,和来源没关系

二、合法的 Referer 值从哪找?

按优先级来

1. 【最准:正常流程抓包拿】

有高权限账号、能正常操作的时候,这是黄金标准:

  1. 用有权限的账号正常走一遍流程
  2. 从页面里点按钮发起合法请求
  3. Burp 抓包,直接抄请求里的 Referer 头的值
  • 优点:100% 准确,完全匹配校验规则
  • 场景:靶场、有测试账号的时候最常用,也就是你这道题的做法

2. 【最常用:按页面层级反推】

实战里 80% 的情况,不用抓包也能猜对。

这是浏览器的默认行为,也是开发的默认逻辑:

你在 A 页面点击按钮,发起 B 接口的请求,那么 B 请求的 Referer 就应该是 A 页面的地址。

所以:

  • 管理面板里的升级/删除用户操作 → Referer 就是 /admin
  • 商品详情页的下单/收藏操作 → Referer 就是商品详情页路径
  • 个人中心的改密码/改信息操作 → Referer 就是个人中心路径

直接把「操作的上一级页面地址」当 Referer 填,绝大多数系统都能过。

开发做 Referer 校验的时候,基本都是按浏览器这个默认行为写的,不会特意搞奇怪的规则。

3. 【前端扒:代码里找规则】

如果是前后端分离的站,直接搜前端 JS:

  • 搜关键词:referer、source、origin
  • 经常能直接看到校验逻辑,比如 if (referer.indexOf('/admin') > -1)

你不仅能知道要加 Referer,还能知道校验的严格程度——是只要包含关键字就行,还是必须完全匹配。

4. 【兜底:按优先级蒙】

实在没线索的时候,按这个顺序试,命中率从高到低:

  1. 操作的上级页面路径(比如 /admin)
  2. 网站根域名(https://xxx.com/)
  3. 接口本身的路径
  4. 空 Referer(直接删掉 Referer 头)

常见信息来源:

来源 能拿到什么
前端 JS 扒代码 直接搜到校验逻辑、合法 Referer 规则
正常操作抓包 直接拿到合法请求的 Referer 原值
开发命名惯例反推 操作的上级页面就是合法 Referer
同类接口类比 普通功能的校验规则,套用到管理功能

三、实战里的常见坑和技巧

1. 校验松紧程度天差地别

不同系统的校验严格程度完全不一样,从松到紧挨个试:

  • 最松:只要有 Referer 头就行,内容随便写
  • 宽松:只要包含域名就行,路径随便
  • 中等:只要包含路径关键字(比如包含 admin)就行
  • 严格:必须完整匹配路径,多一个参数都不行

实战建议:先试完整的上级页面地址,不行再简化成只留域名。

2. 反向操作:删掉 Referer 反而能过

有些系统的逻辑是:

有 Referer 才校验来源对不对;没有 Referer 的时候,走降级逻辑,直接放行。

遇到拦截的时候,除了加正确的 Referer,也可以试试直接删掉 Referer 头,经常有惊喜。

3. 一个常见误区

不用带页面的参数,比如不用写成 /admin?xxx=yyy。 绝大多数 Referer 校验只校验到路径部分,参数不影响,写多了反而可能匹配不上。

Referer 校验本质上是**「把浏览器的默认行为当成了安全机制」**,属于非常弱的访问控制——因为这个头客户端可以随便改。 识别它的核心就是那句话:同样的参数身份,从页面点就好使,直接访问就不行。 遇到这个现象,先伪造 Referer 试,基本都能绕过去。

标准测试顺序(遇到 403 拦截时)

遇到接口拦截,按这个优先级挨个试,哪个成了就是哪种问题:

  1. 改方法:POST 改 GET,参数移 URL 里
  2. 路径绕过:加 X-Original-URL 头
  3. 来源绕过:伪造 Referer、Origin
  4. 域名绕过:改 Host 头、加 X-Forwarded-Host
  5. IP 绕过:加 X-Forwarded-For: 127.0.0.1

总结:

信息搜索第一步,明确执行路径?

授权渗透 / SRC合规挖洞场景下,当前业内通用的实战级信息搜集标准流程,严格遵循「先被动后主动、先轻量后重量级、最小流量接触」原则,全程以合规为前提。

阶段0:合规前置(必须第一步,跳过违法)
  1. 确认书面授权范围:目标域名、IP段、测试时间窗口
  2. 确认边界:是否允许扫描、是否禁止拒绝服务/暴力破解等操作
  3. 明确数据处理规则:禁止泄露、测试后清理痕迹
阶段1:被动信息搜集(OSINT,零流量接触目标)

核心:完全不向目标服务器发请求,通过公开数据源拿信息,无任何风险,是SRC挖洞的主力信息来源。 执行顺序:

  1. 资产归属确认:ICP备案、工商信息,确认目标资产边界,避免越界测试
  2. 子域名枚举
    • 工具:fofa、hunter、quake、crt.sh、subfinder(被动模式)
    • 产出:所有子域名、关联域名、业务系统入口
  3. IP与端口资产普查
    • 工具:shodan、fofa、quake
    • 产出:IP段、开放端口、服务组件初步指纹
  4. 技术栈与组件识别
    • 工具:fofa指纹、Wappalyzer在线查询
    • 产出:CMS、中间件、编程语言、框架版本
  5. 公开代码泄露排查
    • 平台:GitHub、Gitee、GitLab
    • 搜索关键词:目标域名、password、apikey、secret、admin、接口路径
    • 产出:源码泄露、API密钥、配置文件、后台地址
  6. 历史网页归档
    • 工具:Wayback Machine(archive.org)、Common Crawl
    • 产出:已下线旧页面、历史后台路径、废弃接口、参数
  7. 公开文档收集
    • 渠道:企业官网、招聘网站、技术博客、文库
    • 产出:系统架构、内部系统名称、技术选型
阶段2:轻量主动预检(正常用户流量,低风险)

核心:模拟普通用户正常访问,不发异常请求,几乎不会触发WAF/IDS告警。 执行顺序:

  1. 站点基础访问

    • 手动浏览器访问首页、各栏目页
    • 查看响应头:Server、X-Powered-By、Cookie指纹
    • 查看404/403页面,识别CMS指纹
  2. 标准敏感文件预检

    (手动逐个访问,10秒完成)

    • /robots.txt、/sitemap.xml
    • /.well-known/security.txt(海外站点必查,国内大厂逐步普及)
    • /humans.txt、/crossdomain.xml
  3. 前端源码审计

    • 右键查看源码,搜索HTML注释中的敏感信息
    • F12 → Sources,遍历所有JS文件,关键词:admin、panel、api、token、key、debug
    • 产出:隐藏后台路径、未授权API接口、硬编码密钥
  4. 被动链接爬取

    • 工具:Burp Suite 被动代理
    • 正常浏览网站,自动收集所有链接、接口、参数
    • 禁止:主动深度爬虫、暴力爬取
  5. 认证入口盘点:记录所有登录页、注册页、找回密码页路径

阶段3:定向主动探测(授权前提下,谨慎执行)

核心:只针对前面发现的资产做精准探测,不盲目全端口、全路径爆破,避免触发告警封禁。 执行顺序:

  1. 资产存活验证
    • 工具:httpx
    • 批量验证被动阶段发现的子域名是否存活,筛选有效资产
  2. 精准端口服务探测
    • 工具:nmap
    • 只针对已知IP扫描常用端口+重点端口,禁止全端口暴力扫描
    • 轻量版本探测:-sV
  3. 目录与文件探测
    • 工具:ffuf / dirsearch
    • 原则:小字典(精选敏感路径)、低线程(10以内)、加延时
    • 重点:后台路径、备份文件(.bak/.zip/.sql)、配置文件、测试页面
    • 禁止:大字典全路径爆破
  4. 漏洞指纹匹配
    • 工具:nuclei
    • 针对已识别的组件版本,调用对应POC批量验证
    • 禁止:全POC库扫射
阶段4:信息整合与攻击路径规划
  1. 整理资产清单:建立「域名→IP→端口→服务→组件版本」对应关系
  2. 汇总敏感点:后台地址、API接口、泄露密钥、已知漏洞
  3. 攻击优先级排序:
    • 第一优先级:源码泄露密钥、直接可访问后台、已知RCE组件
    • 第二优先级:越权接口、弱口令入口、文件上传点
    • 第三优先级:普通注入、XSS等前端漏洞

前端源码如何快速发现所需内容?

==「先快后慢、先高价值后低价值、先手工后工具」==

一、先明确:找什么?(价值优先级从高到低)

  1. 硬编码凭证:云密钥、API Key、Token、数据库账号密码(直接构成高危漏洞)
  2. 隐藏路径:管理后台、内部页面、测试页面、备份文件入口
  3. API接口清单:后端接口地址、内部私有接口、未鉴权接口
  4. 敏感注释:开发遗留的账号、路径、运维说明、测试标记
  5. 调试开关:隐藏参数、调试模式、测试功能入口
  6. 组件指纹:前端框架、插件版本(对应已知通用漏洞)

二、手工极速审计流程(单点目标,5分钟内完成)

适合单个站点快速摸排,不用装额外工具,浏览器自带功能搞定,实战首选。

阶段1:HTML源码预检(1分钟,Ctrl+U)

打开目标首页,右键「查看网页源代码」,全局搜索(Ctrl+F)按优先级扫:

  1. 最高优先级:搜 <!-- 快速遍历所有注释,开发最容易在注释里遗留后台地址、测试账号
  2. 凭证关键词:password secret key token ak sk api_key
  3. 路径关键词:admin manage backend internal test dev panel
  4. 隐藏表单:<input type="hidden"> 标签里的token、接口参数

小技巧:直接拉到页面源码最底部,很多站点会在页脚留仅源码可见的隐藏管理入口。

阶段2:JS全局深度扫描(2分钟,F12开发者工具)

这是最核心的一步,90%的有价值信息都藏在JS里。

  1. 按F12打开开发者工具,按 Ctrl+Shift+F 打开「全局搜索」,可以跨所有已加载的JS、CSS、HTML文件检索

  2. 按优先级搜索核心关键词,每类搜1-2个代表性词快速定位:

    • 凭证类:apiKey secretKey access_token Authorization
    • 路径类:/admin /api/ /internal path:
    • 接口类:baseURL baseUrl fetch( axios.
    • 路由类:path: children: (Vue/React路由表,直接输出全量页面路径)
  3. 优先排查的JS文件

    (不用所有JS都看,抓主包即可):

    • 名称带 app main index common 的主打包文件
    • 名称带 admin manage 的业务专属JS
    • 文件体积最大的1-2个JS(通常是核心业务包)
阶段3:高价值点专项核查(2分钟)
1. Sourcemap 泄露检测(实战最高发,杀伤力最强)

绝大多数前端项目用Webpack/Vite打包时,生产环境会遗漏删除 .map 源映射文件,可直接还原完整前端源码。

  • 检测方法:找到主JS文件路径,末尾拼接 .map 直接访问 例:https://xxx.com/static/js/app.abc123.js → https://xxx.com/static/js/app.abc123.js.map
  • 如果返回一大段结构化JSON,说明存在泄露;用 reverse-sourcemap 工具可一键还原出完整项目源码,所有路径、密钥、业务逻辑一览无余。
2. 前端配置文件

直接尝试访问常见配置路径:

  • /config.json /settings.json /app.config.json
  • /env.js /config.js /global.js 大量站点会把接口基地址、环境参数、功能开关直接放在前端可访问的配置文件里。
3. 调试/隐藏功能开关

搜索 debug test dev,查看是否存在 if(window.debug) 这类判断逻辑,通常在URL加参数 ?debug=1 即可开启隐藏的调试面板。

三、批量自动化流程(SRC多资产批量挖洞)

当你有几十上百个子域名时,手工逐个排查效率太低,用工具批量初筛,再人工复核高价值目标。

1. 批量提取所有JS文件
  • subjs

    :被动爬取站点所有JS链接,无攻击性

    subjs -i targets.txt | tee js_list.txt
    
  • LinkFinder:深度解析JS文件,提取其中所有URL和路径

  • Burp Suite:开启被动爬虫,正常浏览站点的同时自动收集全量JS文件

2. 批量敏感信息扫描
  • SecretFinder:专门扫描JS中的密钥、Token,内置云密钥特征正则(阿里云、腾讯云、AWS等),误报率低
  • JSFinder:批量提取JS中的接口路径、后台地址
  • Nuclei:调用现成的JS信息泄露POC批量检测,覆盖sourcemap泄露、配置文件泄露、硬编码密钥等场景
3. 人工复核

工具筛出疑似存在敏感信息的目标,再人工进入确认实际价值,过滤误报。

四、实战高频关键词清单(直接拿去搜)

高危凭证类
access_key` `secret_key` `api_key` `apikey` `accessToken` `secretToken` `password` `pwd` `token` `Authorization` `LTAI` `AKID` `sk-
路径接口类
admin` `manage` `backend` `internal` `test` `dev` `debug` `panel` `dashboard` `api/` `v1/` `baseURL` `router` `path:
注释敏感类
TODO` `FIXME` `临时` `测试` `账号` `密码` `入口` `注意

五、实战避坑与进阶技巧

  1. 不要只搜完整单词:打包混淆后的JS经常出现 a="/admin" 这种写法,搜 /admin 比搜 admin 命中率更高
  2. 关注路径拼接:很多路径是 base + '/admin' 动态拼接的,要结合上下文还原完整地址
  3. Burp配合提速:Burp的全局「Search」功能可以检索所有历史请求响应,代理浏览的同时自动完成扫描
  4. 优先看H5端:大量站点的移动端H5页面审核比PC端宽松,更容易泄露后台路径和密钥
  5. 测试环境价值更高:子域名中的 test dev uat 环境,JS里的敏感信息通常是生产环境的数倍

怎么第一眼判断这些不同情况的漏洞的存在?

请求从浏览器到后端,再从后端回到浏览器的完整链路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

flowchart TD
A["用户操作网页"] --> B["浏览器构造 HTTP 请求<br/>Method、URL、Headers、Cookie/Token、Body"]
B --> C["DNS 解析域名<br/>获取目标服务的 IP 地址"]
C --> D["建立网络连接<br/>TCP + TLS,或 HTTP/3 使用 QUIC"]
D --> E["CDN / WAF / 边缘层(可选)"]
E --> F{"边缘缓存命中?"}
F -- 是 --> R["返回缓存响应"]
F -- 否 --> G["反向代理 / 负载均衡(可选)<br/>TLS 终止、转发、限流"]
G --> H["Web 服务器 / API Gateway(可选)"]
H --> I["应用入口<br/>路由匹配、请求解析、中间件、日志"]
I --> J{"认证 Authentication<br/>用户身份是否有效?"}
J -- 否 --> X["返回 401 / 登录跳转等"]
J -- 是 --> K["建立用户身份上下文<br/>Session、Principal、SecurityContext 等"]
K --> L{"授权 Authorization<br/>当前用户能否执行此操作?"}
L -- 否 --> Y["拒绝访问<br/>常见为 403,也可能返回 404"]
L -- 是 --> M["Controller / Handler<br/>接收并处理请求"]
M --> N["Service / 业务逻辑<br/>处理业务规则,必要时再次检查权限"]
N --> O["DAO / Repository / ORM<br/>组织数据查询或更新"]
O --> P["数据库 / 缓存 / 其他内部服务"]
P --> Q["返回数据,组装响应<br/>序列化、异常处理、HTTP 状态码"]
Q --> S["反向经过相关网络层<br/>代理、缓存策略等(视架构而定)"]
X --> S
Y --> S
R --> T["浏览器接收响应"]
S --> T
T --> U["浏览器解析响应<br/>渲染 HTML 或更新前端页面"]

classDef security fill:#fff0d8,stroke:#c18427,color:#5c3b0b
class J,K,L,N security

把这张图拆成 5 个阶段理解

阶段 1:浏览器准备并发送请求

用户点击“查看订单”,浏览器可能发送 GET /api/orders/123。请求除了 URL,还可能带有 Cookie、Authorization 请求头和其他参数。

安全关注点:请求参数可被用户自行修改。前端页面展示了什么,不代表后端收到的请求就可信。

阶段 2:经过网络入口和流量转发层

DNS 解析、网络连接、CDN、WAF、反向代理、负载均衡等环节负责把请求送到正确的服务。有些环节还会做 TLS 终止、限流或缓存。

安全关注点:代理配置、请求转发规则、缓存隔离和信任边界。边缘层的拦截并不能替代应用内部的权限校验。

阶段 3:应用识别用户并判断权限

应用先通过 Session、Cookie 或 Token 等机制识别用户身份,再判断这个用户能否访问指定资源、执行指定操作。

安全关注点:这是访问控制的核心。认证(是谁)和授权(能做什么)是两个不同的问题。

阶段 4:执行业务逻辑并访问数据

Controller 接收请求,Service 执行业务流程,DAO、Repository 或 ORM 访问数据库,也可能调用其他服务。

安全关注点:即使入口做过权限检查,业务逻辑或数据查询也可能遗漏资源所有权、租户边界等约束。

阶段 5:生成响应并返回浏览器

服务把结果组织成 HTTP 响应,经过相应网络层返回浏览器,浏览器再展示页面或更新前端状态。

安全关注点:敏感数据可能在响应中泄露;共享缓存配置不当也可能造成不同用户之间的数据泄漏。

==业务代码长什么样、请求在哪一层被处理,会随着架构改变==

  1. 传统单体架构:适合理解 Java Web 的基本请求链路

    image-20261010171947114

  2. 前后端分离 + API 架构
1
2
3
4
5
6
7
8
9
10
11
12
13

flowchart TD
A["浏览器中的 Vue / React 页面"] --> B["发送 HTTP API 请求"]
B --> C["API Gateway 或后端入口(可选)"]
C --> D["后端认证:识别用户身份"]
D --> E["具体 API:检查操作权限和资源归属"]
E --> F["业务逻辑 / 数据访问"]
F --> G["返回 JSON 等响应"]
G --> H["前端更新页面"]

A -. "前端隐藏按钮不是安全边界" .-> B
E -. "真正的权限校验必须由可信后端完成" .-> F

3.微服务架构:一个请求可能经过多个后端服务

在微服务架构中,API Gateway 往往把请求转发给不同的服务。一个业务操作还可能触发多个内部服务之间的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

flowchart TD
A["浏览器"] --> B["API Gateway"]
B --> C["验证 Token / 基础访问策略"]
C --> D["订单服务"]
D --> E["库存服务"]
D --> F["支付服务"]
E --> G[("库存数据库")]
F --> H[("支付数据库")]
D --> I[("订单数据库")]
I --> J["聚合结果并返回"]
J --> A

K["资源级权限校验"] -.-> D
K -.-> E
K -.-> F

4. CDN、反向代理与共享缓存:请求可能根本没有进入后端

还有一种特殊情况很值得单独看,因为它可能让人误判后端代码的行为。

假设网站使用 CDN 或反向代理缓存页面。正常情况下,服务器处理用户请求并返回订单详情;但如果缓存配置不当,某些包含用户数据的响应可能被错误地复用给其他用户。

潜在问题包括:

  • 缓存键没有正确区分不同用户的请求。
  • 本应只对特定用户可见的响应被共享缓存。
  • 缓存策略允许敏感响应被缓存或复用。

不过,不能把“用了 CDN”直接等同于“有漏洞”。是否存在风险,要看哪些响应被缓存、缓存键怎样构造、缓存指令如何设置,以及认证请求会不会命中共享缓存。

这篇还差一个场景总结和排版整理,其他都弄完了。2026.10.13