01
背景
在越权漏洞自动化检测领域,如何提高检测准确率是一个长期困扰业界的难题。2022年末开始,字节安全团队与电商质量保障团队在此项工作中加大投入、通力合作,从最初通过规则优化策略的初见成效,到陷入瓶颈,再到引入大语言模型(LLM)的再次突破,在问题的分析解决、方案的调研落地过程中积累了一些经验,本文将对方案中关键步骤之一的基于 LLM 的公共信息接口识别能力建设进行介绍。
黑盒越权检测准确率趋势图
黑盒越权检测准确率提升经历了以下两个阶段:
最初采用基于规则的误报优化策略,过程中不断完善规则(如:异常响应识别规则、响应相似度计算规则等),检测准确率自2023年初不足20%提升至2024年Q2的35% ,随后陷入瓶颈难以持续提升。
引入 LLM 优化方案,检测准确率目前提升至55%:通过误报归因分析,我们识别到TOP1原因为公共信息接口(接口设计允许不同用户获取相同信息,且该信息不涉及私有数据),该类误报占比30%而 LLM 的语义理解、逻辑推理等优势恰好可以用于解决此类问题,公共信息接口识别能力建设成为了我们使用 LLM 提升越权检测准确率的切入点。
02
基于LLM的公共信息接口识别能力建设
公共接口可以分为两种情况:读接口与写接口
读接口主要指接口功能主要是读取数据,而读公共接口则是指读取的信息是公共可访问的。
例如,某接口返回ubuntu节点的可用区,这对业务系统来讲是一个公共信息,因为无论哪个合法用户都有权限访问此信息,且获取的信息也是相同的:
- curl: curl -X POST -d {"node_type": "ubuntu"} --compressed https://example.com/api/get_item_available_space_info
- resp body: {"result":{"available_zone":{"beijing","shanghai", 'guangzhou', 'shenzhen'}}}
与之相对,写接口的主要功能是写入数据,写公共接口则是指对应信息的写入不会影响到其他用户的私有数据。
例如,某接口用于提交ToB商品的售前咨询信息(姓名、电话、公司、咨询问题等),方便销售人员与潜在客户快速建立联系,对业务系统来讲,任何一个合法用户都有权限提交此类信息,因此这同样是一个公共信息接口。
- curl -X POST -d {"name": "zhangsan", "phone":"13888888888", "company":"bytedance"} --compressed https://example.com/api/sales/submit_info
- resp body: {'Result': 'Success'}
但是如果不在预先已知是一个提交售前咨询表单的情况下,通过请求与响应信息,我们只能知道这是一个提交个人信息成功的请求,可能是修改个人联系信息?也可能是成功创建了订单?对于当前接口是否是公共信息接口,我们并不能给出确切结论。
与写接口相比,在判断读接口是否为公共信息接口时,请求和响应返回的信息更加的充分,可以只依据请求和响应就能做出判断,因此我们先从简单问题下手,使用 LLM 来识别特定读接口是否为公共信息接口。
2.1 读接口的公共信息接口识别
入门——Prompt Engineering
角色定位
为了让LLM更好地理解任务,我们在 prompt 中对 LLM 角色的目标和技能等进行了约束,如下:
# 目标
检查以curl命令样式提供的API接口和相应的响应,以确定该API请求及其响应是基于当前用户和请求中提供的资源id响应的个性化数据,还是所有用户都可以访问的公共信息。如果是非个性化数据,则认为当前API接口响应跨用户可访问信息。
# 分析
- 提供给你的所有 API 接口都是**只读**, 你应当考虑API接口的响应是个性化信息还是跨用户可访问信息。
# 技能
1. 网络安全知识:利用您对安全漏洞的深刻理解来评估所提供的 API 端点的响应的跨用户可访问性。
2. 分析能力:对端点和响应进行细致的分析,以确定相同内容返回给不同用户的情况。
3. 沟通清晰:清楚地传达您的发现,强调跨用户可访问性的概念及其对安全的影响。
4. 关注细节:密切关注响应结构和身份验证机制,以确保分析全面。
测试集
为更有效地定量分析模型、提示词等对公共信息接口的识别能力,需构建测试集。以黑盒扫描历史中已发单且经人工处理的越权工单作为原始素材,提取对应的人工运营处置原因,以此判断是否为公共信息接口,具体判断逻辑如下:
非公共信息接口:已修复完成工单对应的接口均认定为非公共信息接口。
公共信息接口:若工单被标记为误报,且误报原因属于以下情况之一的,其对应接口判定为公共信息接口:公共信息接口、流量为无效响应、流量为兜底响应、正常业务逻辑。
依据上述逻辑,自动筛选出 42 条公共信息接口和非公共信息接口作为测试集。依据此统一标准,对各项性能指标的优化举措进行评估。
测试效果
在明确了基本的 prompt 框架后,我们开始对 prompt 进行调优。最初的 prompt 在使用 Doubao-pro-32k 模型的评测结果如下:
可见模型对正、负样本的区分判断能力均较差,尤其是正样本召回率仅 36.36% 。
进阶——Few-shot
对模型来说,单纯的prompt可能会非常抽象,就像数学书的公式。为了让模型更好地推理,我们可以给出公共接口与非公共接口的示例,类似数学书上的例题。示例可以让模型更好地理解我们的指令。
Few-shot 即在 prompt 中提供示例,以辅助 LLM 进行判断。我们随机梳理了 10 条工单相关的请求响应信息作为 few-shot 添加到了 prompt 中进行优化,其中正样本(公共信息接口)3条,负样本(非公共信息接口)7条。
# 目标
检查以curl命令样式提供的API接口和相应的响应,以确定该API请求及其响应是基于当前用户和请求中提供的资源id响应的个性化数据,还是所有用户都可以访问的公共接口信息。如果是非个性化数据,则认为当前API接口响应跨用户可访问信息。
...<origin_prompt>...
# 示例
## 示例1
- curl: curl -X POST -d {"node_type": "ubuntu"} --compressed https://example.com/api/get_item_available_space_info
- resp body: {"result":{"available_zone":{"beijing","shanghai", 'guangzhou', 'shenzhen'}}}
- 结论: 'is public': 'Yes', 接口返回的是节点可用区的范围,响应信息中响应了不同可用区中的节点实例情况,所有用户都可以访问,而不是一个专属于自己的敏感信息,因此响应的是跨用户可访问信息
## 示例2
- curl: curl -X POST -d {"Name": "test", "Pagination": {"PageNum": 1, "PageSize": 0}} --compressed https://example.com/api/get_self_contact_info
- resp body: {"Result":{"Data":[{"Description":"","Id":"112233","Name":"test","Persons":[{"Email":"[email protected]"}]}],"Pagination":{"PageNum":1,"PageSize":0,"Total":1}}}
- 结论: 'is_public': 'No', 返回信息中包括id,这些信息应当是仅自己(当前用户可以访问的),因此响应的不是跨用户可访问信息
...<更多示例>...
同时我们也扩充了测试集的数量(200+)以期更好地通过测试结果来反映 LLM 能力在实际业务场景使用中的表现。第一次测试结果如下:
可以看到,在提供了 few-shot 之后,整体的精确率提升到了 66.91%,对正样本的识别率更高,但是负样本的识别率较差,因此接下来在 few-shot 中提供更多负样本的示例。再次测试结果如下:
增加了较多负样本后,可以明显看到 LLM 对负样本的识别更准确,但是受其影响,正样本准确率下降。
保持一定负样本的数量前提下,再次增加 few-shot 中正样本的数量进行测试,结果如下:
可以看到更多的正样本被识别到,由此我们的 LLM 能力可以认为对正样本有了更好的识别能力,但是 FP 的数量依然很高。FP 即本身并不是公共信息接口,但被 LLM 错误地识别为了公共信息接口。从越权检测角度看,因 FP 造成的漏报是更不可接受的,我们需要进一步降低 FP 的数量。
在提供了更多针对 FP 的 few-shot 示例后,我们得到的测试结果如下:
此时,我们使用 LLM 针对读接口的公共信息接口识别准确率维持在了 70% 左右,如果进一步将 FP 的数量降低,同样也会影响 TP 的数量,few-shot 的提升效果已经达到了瓶颈。
再进阶——Retrieval-Augmented Generation(RAG)
还有别的方法吗?有,还是举例子🌰,但是动态地举例子。可以找与当前需要判断的数据相似的例子举。例如当我们需要判断get_docker_price
的接口是否是公共信息接口时,我们希望提供的参考可能是get_k8s_prices
,get_object_store_price
的例子,他们都是获取特定产品价格的接口,如果已知get_k8s_prices
,get_object_store_price
是公共信息接口,那么显而易见:get_docker_price
同样是公共信息接口。
RAG 技术与 few-shot 相似,也是提供给 LLM 更丰富的示例,而 RAG 技术的优势在于可以通过检索能力,根据提供的请求信息动态地从海量知识库中检索更加相似的示例。RAG 系统的效果很大程度上依赖于检索步骤的准确、相关性,这也为我们的调优提供了方向。在应用 RAG 的过程中,我们针对使用 RAG 的各项参数进行控制变量的实验,以期找到最优的配置组合。
最终可以认为在使用 FLAT 索引算法 + Float 量化方式 + 豆包多功能向量模型并在知识库中提供resp body信息 + 标注正负样本的情况下,可以使 RAG 的效果最大化。从实际应用角度来看,81.13% 的准确率与 93.47% 的召回率已具备了落地实践的可行性。
叒进阶——Reranker & Two-Stage Retrival
上文提到 RAG 技术的效果很大程度上依赖于检索的准确性,目前 RAG 主要使用语义检索(semantic search)的方式将用户输入转化成向量结果在向量数据库中进行搜索从而找到最近邻。为了实现对数据的快速搜索,语义检索技术试图将所有的信息压缩到一个多维向量中,这种行为在提高检索速度的同时也导致了信息的丢失,可能遗漏大模型需要的最关键信息。
那就让大模型自己来判断谁是更准确的例子!
为了解决信息丢失的问题,提高检索能力的召回率,我们引入了Reranker(重排序器)和Two-Stage Retrival(两阶段检索)。与向量搜索不同,Reranker 直接使用 Transformer 处理原始信息,这让我们能够针对具体的查询场景,获得针对当次查询的相似度最高的信息。但是效果提升的同时,Reranker 的代价是需要更多时间。因此,在使用Reranker时,一般采用 Two-Stage Retrival 的方式,首先使用向量搜索技术获得一定量的召回信息后,再对这些召回信息使用 Reranker 进行重排序,从而以较低的时间代价获得更高相似度的检索结果。
2025年Q1,团队进行了一系列评测实验,过程及评测效果如下:
通过评测,可以发现公共信息接口和非公共信息接口最好的效果均为测试8:使用 RAG召回 top50 的知识条目,获取 Reranker 结果 top5 添加在 Prompt 中使用。我们最终在线上也使用了此方案。使得黑盒扫描越权检测中使用LLM 识别读公共信息接口的准确率:83.20%,召回率:82.57%。
2.2 写接口的公共信息接口识别
对比读接口,在判断写接口是否为公共信息接口的时,仅使用请求和响应信息即使对人类来说也是一个较为困难的任务。正如我们在文章最开始举的例子:
- curl -X POST -d {"name": "zhangsan", "phone":"13888888888", "company":"bytedance"} --compressed https://example.com/api/sales/submit_info
- resp body: {'Result': 'Success'}
写接口的响应中可能只有较少的信息:{'Result': 'Success'}
,如果仅基于请求和响应进行判断,可能导致很高的误判。因此,让 LLM 来判断写接口是否是公共信息接口除请求和响应信息之外,我们还需要额外提供更多信息供 LLM 参考。
团队选择了请求涉及的 SQL 语句。SQL 语句中往往提供了写操作对应的表信息、列信息,这些信息对于公共信息接口的判断来说至关重要。
同样对于上述示例,如果提供对应的SQL语句如下:
INSERT INTO pre_sales_service (
customer_name, customer_phone, customer_company, description, status, created_at)
VALUES ('zhangsan','13888888888', 'bytedance','咨询是否存在优惠', '待沟通', CURRENT_TIMESTAMP);
我们能够确切的判断:这是一个用于提交售前咨询信息的接口,显然属于公共信息接口,因任何合法用户均可提交售前咨询单。
SQL 预处理相关 LLM 能力建设
在进行写接口的公共信息接口识别能力建设前,首先建设了2项对SQL语句进行预处理的LLM能力:
对多个 SQL 进行清洗去重
不论是原始请求还是替换 cookie 后重放的越权检测请求,请求过程中均可能涉及到多条SQL 语句的执行,且两个请求涉及的 SQL 语句可能存在数量、字段值上的差异。我们通过 LLM 将两个请求涉及的所有写操作 SQL 进行对比,去重掉功能相同的SQL 。例如对于如下 SQL:
# 原始请求 SQL
SELECT * from order_task WHERE id = 738769923
UPDATE order_task SET fail_reason='当前商家已有员工跟进,暂不可发单',status=30,update_time='2024-07-04 16:46:13.984' WHERE id = 738769923
# 越权检测请求 SQL
SELECT * from order_task WHERE id = 738769923
UPDATE order_task SET fail_reason='当前商家已有员工跟进,暂不可发单',status=30,update_time='2024-07-06 10:30:11.166' WHERE id = 738769923
最终通过该能力可提取出关键写操作:
UPDATE order_task SET fail_reason='当前商家已有员工跟进,暂不可发单',status=30,update_time='2024-07-04 16:46:13.984' WHERE id = 738769923
获取 SQL 的自然语言描述
使用 LLM 对 SQL 语句进行一句话总结,说清楚 SQL 语句操作的对象表、字段、条件和主要功能,用于 LLM 进行公开接口判断和告警运营,例如上述提取出的关键写操作 SQL,大模型能够将其描述为:
该 SQL 操作是对 order_task 表中 id 为 738769923 的记录进行更新,设置失败原因为“当前商家已有员工跟进,暂不可发单”,将状态更新为 30,并设置更新时间为 2024-07-04 16:46:13.984
LLM写接口公共信息接口识别能力建设
从上图中可以看出,写接口的公共信息接口识别相比于读接口,保证效果的关键在于引入请求涉及的 SQL 语句,目前我们主要从各种业务日志中进行了 SQL 语句的获取。
在大部分复用了上述读接口的公共信息接口识别能力的基础上,我们可以在 prompt 中额外添加自然语言描述的 SQL 以及他们操作的数据信息给 LLM 进行分析。
Prompt:
<前序部分与读公共信息接口相同>
---额外的补充---
# sql信息
## 下面提供给你的是当前端点使用不同的鉴权信息和相同的请求参数操作了的相同列的SQL操作信息(使用自然语言描述),你需要参考:n
<sql相关信息>
在25年Q1黑盒扫描通过LLM判断写接口公共信息接口的准确率:76.80%,召回率:75.39%。
03
后续计划
写接口能力丰富
目前用于写接口的 LLM 在判断的准确率和召回率方面依然较低,需要借助公司的基础设施建设、交互式应用安全测试(IAST)等手段,把更丰富的 SQL 信息补充到提示词 prompt 里,让 LLM 来分析判断,这样能更好地优化和减少写接口相关的越权误报。
MCP 能力集成
MCP 作为一个开源协议,如同 USB 接口一样,赋予了大语言模型更强的拓展性。当前使用外部数据时,需预先人工提取并处理好后提供给模型使用。然而,随着 MCP 的兴起,可以将选择读取哪些信息(日志、SQL等)、选择什么时候需要读取信息的权限转交给 LLM,使 LLM 能够获得对其工作更具价值的数据。
04
期待交流
在越权检测准确率的优化过程中,我们充分利用了公司豆包基座模型的快速迭代优势,通过多次模型版本的升级获得了更好的检测效果,目前已在越权检测系统中使用最新的多模态深度思考模型Doubao-Seed-1.6。随着 LLM 能力的不断增强,我们相信其在安全漏洞检测领域将发挥更大价值,将能够有效解决诸多传统方法难以应对的问题。
在应用实践方面,除成功运用 LLM 识别公开信息接口外,我们还针对常见越权检测误报场景进行了其他探索,如:响应有效性判断、越权写入结果验证等关键环节。同时,我们也应用 LLM 技术提升了传统 Web漏洞检测的准确率和召回率。关于这些技术实践的具体细节,字节安全团队将在后续系列文章中详细分享,欢迎持续关注。如有任何问题,欢迎通过公众号留言或线下交流探讨。
无恒实验室是由字节跳动顶尖安全专家组成的专业攻防研究团队,为字节跳动全系产品与业务安全保驾护航。通过漏洞挖掘、攻防实战、黑产打击、高效应急等核心能力,系统性提升公司基础安全与业务安全防护水平,最大限度降低安全事件对业务及公司的潜在影响。
同时,无恒实验室致力于构建开放协作的网络安全生态,持续向业界输出研究成果,协助行业降低安全风险,并积极寻求与行业伙伴的合作创新,共同为网络安全生态建设贡献力量。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...