Liferay集合提供程序授权缺失漏洞(CVE-2023-33952)深度剖析与修复 📅 2026/6/20 21:06:28 1. 项目概述一次对Liferay授权边界的深度审视最近在梳理一个基于Liferay DXP构建的企业门户安全基线时无意间踩到了一个“授权缺失”的坑。这个漏洞的官方编号是CVE-2023-33952听起来平平无奇但其背后的逻辑和潜在影响却让我对Liferay这类大型平台化产品的权限模型有了更深的思考。简单来说这个漏洞的核心在于Liferay Portal和DXP的“集合提供程序”功能在某些特定配置下未能正确校验当前用户是否有权限访问其聚合的某些子内容导致低权限甚至未授权用户可以绕过前端限制直接访问到本不该看到的数据。这可不是简单的页面越权它触及了门户内容聚合架构的信任边界问题。想象一下你搭建了一个公司门户首页上通过“最新文档”、“部门新闻”、“项目动态”等多个内容块即“集合”来聚合展示来自不同站点、不同权限区域的信息。作为管理员你精心配置了每个集合的显示规则以为万事大吉。但这个漏洞的存在意味着攻击者可能通过直接调用集合提供程序的底层API或者构造特定的请求绕过你精心设计的展示层权限控制像“透视”一样看到集合背后那些本应对他隐藏的条目。这对于依赖Liferay进行敏感信息分发的企业来说无疑是一个需要严肃对待的风险。本篇文章我将从一个实践者的角度彻底拆解这个授权缺失漏洞的成因、影响范围、复现方法以及修复方案。我不会只停留在官方公告的描述上而是会结合Liferay的架构深入代码层面分析漏洞触发的路径并分享在真实环境中进行安全评估和加固的实操经验。无论你是Liferay的开发、运维还是安全工程师理解这个漏洞都将帮助你构建更健壮的门户应用。2. 漏洞核心原理与架构背景剖析要理解这个漏洞首先得搞清楚Liferay里的“集合”是什么以及“集合提供程序”是如何工作的。这不仅仅是功能层面的了解更需要深入到其数据获取和权限校验的流程。2.1 Liferay集合与提供程序模型解析在Liferay中“集合”是一个逻辑概念用于将分散的内容项如Web内容文章、博客条目、文档等动态地聚合在一起并以小部件Widget的形式展示在页面上。你可以把它理解为一个可配置的、智能的内容查询和展示模块。创建集合时关键的一步是选择“集合提供程序”。Liferay提供了多种内置提供程序手动选择管理员手动挑选特定内容项。动态集合基于预定义的“信息列表”或“类别”来自动筛选内容。自定义通过编写代码或使用其他扩展方式定义集合来源。漏洞主要涉及的是那些能够动态获取内容的提供程序尤其是基于“信息列表”和“类别”的提供程序。这些提供程序的工作流程可以简化为接收上下文提供程序接收页面、用户、站点等上下文信息。执行查询根据配置的筛选条件如列表ID、分类词汇、标签等在后台执行内容查询。应用权限过滤关键步骤理论上查询结果在返回给前端展示之前应该经过一层权限过滤即检查当前用户对每一个查询到的内容项是否拥有“查看”权限。返回结果将过滤后的、用户有权访问的内容项列表返回给集合小部件进行渲染。2.2 授权缺失漏洞的根源定位漏洞就出现在上述流程的第3步——权限过滤的缺失或不完整。在某些版本的Liferay Portal和DXP中部分集合提供程序在后台执行查询时直接使用了不包含权限校验的底层数据访问方法或者权限校验的上下文如当前用户信息未能正确传递到查询的最深层。举个例子假设我们有一个“部门敏感文档”信息列表其权限设置为仅“财务部”成员可查看。我们在门户首页配置了一个集合使用“动态集合”提供程序来源指向这个“部门敏感文档”列表。管理员预期的是只有财务部成员登录后才能在首页看到这个集合及其中的文档。然而存在漏洞的版本中当非财务部成员甚至未登录用户访问该页面时集合提供程序在后台执行查询的代码路径可能类似于// 伪代码示意有问题的流程 public ListContentItem getContentItems(CollectionProviderContext context) { // 获取配置的“信息列表”ID long infoListId getConfiguredInfoListId(); // 直接调用底层服务获取该列表下的所有条目未传入用户上下文进行权限过滤 ListContentEntry allEntries infoListEntryLocalService.getEntries(infoListId); // 转换为集合项并返回 return convertToContentItems(allEntries); }而正确的、安全的代码路径应该像这样public ListContentItem getContentItems(CollectionProviderContext context) { long infoListId getConfiguredInfoListId(); // 调用服务时明确传入权限检查所需的参数如用户ID、作用域组ID等 ListContentEntry filteredEntries infoListEntryService.getEntries( infoListId, context.getUserId(), context.getScopeGroupId(), QueryUtil.ALL_POS, // 起始 QueryUtil.ALL_POS // 结束 ); return convertToContentItems(filteredEntries); }或者更常见的是Liferay的Service层方法本身应该集成了权限检查。但如果集合提供程序错误地调用了LocalService通常用于内部处理绕过权限而非Service对外暴露包含权限逻辑就会导致漏洞。注意这里的代码是高度简化的示意实际Liferay的权限模型涉及PermissionChecker、ResourcePermission等复杂组件。漏洞的本质是权限校验上下文在“集合提供程序”这一特定调用链中丢失或未被应用。2.3 影响范围与风险量化这个漏洞的影响是直接的信息泄露。其严重程度取决于利用此漏洞能访问到的内容敏感度。低风险场景集合聚合的是公开新闻、产品手册等非敏感信息漏洞影响有限。高风险场景集合聚合了包含员工个人信息、内部财务数据、未公开项目计划、合同文档等敏感内容的条目。攻击者利用此漏洞可以系统性地“窥探”这些集合背后的数据池。更令人担忧的是这种漏洞的利用往往“静默”。攻击者不需要暴力破解不需要触发异常日志只需要像正常用户一样浏览页面但通过工具拦截和修改对集合数据的异步请求通常是通过JSON API就可能获取到超权限的数据。在安全检测中这类漏洞容易被传统的Web漏洞扫描器忽略需要有针对性的业务逻辑安全测试才能发现。3. 漏洞复现与验证实操指南理论分析之后我们必须在可控环境中验证漏洞才能真正理解其触发条件。以下是我在测试环境以Liferay DXP 7.4 GA75之前版本为例中的复现步骤。3.1 测试环境搭建与配置环境准备部署一个存在漏洞版本的Liferay DXP实例例如7.4 GA70。确保拥有管理员账号和一个普通用户账号如testuser仅拥有默认权限。创建敏感内容以管理员身份登录创建一个新的“信息列表”命名为“高管通讯”。在该列表中添加几条条目内容可以模拟为“Q1财报会议纪要”、“董事会决议草案”等。关键步骤进入“高管通讯”列表的“权限”设置移除“Guest”和“普通用户”角色的“查看”权限。确保只有“管理员”等特定角色可以查看。创建有漏洞的集合进入页面编辑模式添加“集合”小部件到页面。配置该集合集合来源选择“动态集合”。选择信息列表指向刚才创建的“高管通讯”列表。保存页面。此时以管理员身份浏览可以看到集合中显示了“高管通讯”里的条目。以testuser身份浏览预期应该看不到任何内容因为无权限。3.2 漏洞验证与利用过程现在我们尝试以普通用户testuser的身份绕过前端限制。前端观察使用testuser登录打开包含该集合的页面。浏览器开发者工具切换到“网络”(Network)选项卡。刷新页面观察网络请求。你会看到页面加载后通常会有异步请求去获取集合数据请求URL可能包含/o/headless-delivery/...或/api/jsonws/...等路径参数中会包含集合的ID或配置信息。定位数据请求在这些请求中寻找返回数据格式为JSON、且内容看似为文章或条目列表的请求。这就是集合提供程序在后台获取数据的API调用。权限绕过尝试直接复制这个API请求的URL和完整参数包括Cookie因为已登录。使用一个更强大的HTTP客户端工具如Postman、cURL或Burp Suite Repeater。将请求发送出去。在存在漏洞的环境中即使使用testuser的会话这个API请求也可能返回完整的“高管通讯”列表条目包括其标题、内容摘要甚至完整内容。对比验证为了确认这是漏洞而非配置错误可以尝试直接访问“高管通讯”信息列表的常规展示页面如果有的话testuser应该被拒绝访问或看到空列表。同时尝试调用明确需要权限检查的、获取单个条目详情的APItestuser也应该被拒绝。这种对比能帮助你确认漏洞仅限于“集合提供程序”这个特定的数据获取路径。实操心得在实际测试中浏览器的“网络”选项卡可能因为Liferay的客户端渲染框架而变得复杂。一个更有效的方法是直接查找集合小部件对应的Portlet ID或UUID然后搜索Liferay的Java API文档找到其对应的后端服务端点。使用工具直接调用这些端点是验证这类服务层授权漏洞的最直接方法。3.3 利用场景深度挖掘基础的API直接调用只是开始。一个有经验的安全测试者会思考更多场景组合查询如果集合提供程序支持复杂的筛选器如按标签、分类、自定义字段过滤攻击者是否可以修改这些过滤参数在已越权的数据集中进行更精确的“数据挖掘”影响其他提供程序漏洞报告可能只提及了“信息列表”提供程序但基于相同框架的“分类”提供程序、“自定义SQL”提供程序是否也存在类似问题需要做横向测试。批量信息泄露通过自动化脚本遍历门户上所有的集合ID或配置可以快速测绘出整个门户中所有存在授权缺失的集合点形成一份敏感数据地图。4. 修复方案与安全加固实践确认漏洞存在后接下来就是修复和加固。方案分为立即缓解和根本解决两个层面。4.1 官方补丁分析与应用Liferay官方针对CVE-2023-33952发布了安全修复补丁。对于DXP用户通常以Fix Pack或Hotfix的形式提供。获取补丁登录Liferay官方客户支持门户根据你的DXP版本如7.4 GA查找对应的安全修复公告下载相关的Fix Pack。分析补丁内容在应用前建议有条件的话查看补丁修改的代码文件。通常修复会集中在com.liferay.info.collection.provider.impl相关的类中。修复的核心逻辑必然是确保在InfoCollectionProvider的实现类中所有数据获取方法都正确地传递并使用了InfoRequestContext其中包含用户权限信息或者调用了已经包含权限检查的Service层方法而非LocalService。应用补丁按照官方指南在测试环境先行部署Fix Pack。部署后重复上述漏洞验证步骤确认使用testuser调用相关API时返回的是空数组或权限错误而非敏感数据。回归测试应用安全补丁后必须对门户的关键功能进行回归测试确保修复没有破坏正常的集合显示功能。特别是那些依赖复杂权限模型如组织层级权限、资产库权限的集合。4.2 自定义代码的安全自查与修复如果你在项目中自定义过集合提供程序实现InfoCollectionProvider接口那么你必须手动检查自己的代码。这是一个关键的自查清单检查点安全做法风险做法数据获取入口使用*ServiceUtil或*Service的带权限检查的方法。使用*LocalServiceUtil或直接SQL查询。上下文传递方法参数中包含InfoRequestContext并从中提取userId,scopeGroupId用于查询。忽略InfoRequestContext使用硬编码或默认值。权限显式校验在返回数据前对每个条目调用PermissionChecker.hasPermission(...)进行二次校验。假设底层服务或查询已完全处理权限。服务调用方式通过ServiceContextThreadLocal.getServiceContext()获取当前服务上下文。新建一个空的或默认的ServiceContext。对于发现问题的自定义提供程序修复方法是重构数据获取逻辑。确保从InfoRequestContext中获取正确的用户和范围上下文并将其传递到所有后续的服务调用中。4.3 运维层面的监控与防护在应用补丁的同时可以在运维层面增加一些防护和监测措施WAF规则在Web应用防火墙中可以针对Liferay集合相关的API路径如/o/headless-delivery/v1.0/sites/${siteId}/content-sets/${contentSetId}/contents设置规则对异常的访问模式如未登录用户访问、低权限用户高频访问进行告警或限流。日志审计启用Liferay的详细审计日志特别是针对InfoCollectionProvider相关类的日志。监控是否有大量来自同一低权限账号的对多个不同集合ID的访问请求这可能是自动化探测的迹象。权限最小化原则复查借此机会全面审查门户中所有集合的配置。确保每个集合所引用的源内容信息列表、分类等其本身的权限设置遵循最小化原则。即使提供程序存在漏洞严格的内容源权限也能将损失降到最低。5. 深度防御构建安全的Liferay内容聚合架构修复一个具体漏洞是治标更重要的是建立“深度防御”的思想从架构和开发流程上避免此类问题。5.1 安全开发规范SDL集成对于Liferay二次开发团队应将以下条款纳入开发规范强制代码审查点所有实现InfoCollectionProvider、InfoFilterProvider等扩展点的代码在评审时必须重点审查其权限上下文传递和数据获取方式。使用安全工具在CI/CD管道中集成静态代码分析工具编写或使用现有规则来检测对*LocalService的潜在危险调用特别是在Web上下文可访问的代码中。单元测试要求为自定义集合提供程序编写单元测试必须包含权限测试用例。例如模拟一个无权限用户调用getInfoItems方法断言返回结果为空或抛出权限异常。5.2 权限校验的“纵深防御”策略不要完全依赖Liferay框架或某一层的权限校验。在设计内容聚合功能时考虑多层校验展示层校验集合小部件本身可以根据当前用户角色决定是否渲染。服务层校验核心集合提供程序的业务逻辑必须进行权限校验这是最主要的防线。数据层校验如果内容源来自自定义表或外部系统在数据库查询或外部API调用中也应尽可能加入基于用户身份的过滤条件。内容级校验对于极度敏感的内容可以考虑在内容存储时进行加密并在提供程序中集成解密逻辑而解密密钥的获取与用户权限再次绑定。5.3 定期安全评估与渗透测试指南对于运行重要业务的门户定期进行安全评估是必须的。针对集合和内容聚合功能渗透测试应关注参数篡改测试是否可以通过修改集合ID、站点ID、分类ID等参数访问到其他站点的集合或内容。权限提升测试低权限用户能否通过集合API获取到高权限用户才能看到的内容条目。信息泄露检查API返回的JSON数据是否包含了过多的信息如内部ID、创建者详情、未发布的草稿内容等。批量枚举测试是否可以通过遍历数字ID的方式枚举出系统中所有的集合配置从而发现未链接到页面但可访问的敏感集合。这个关于Liferay集合提供程序的授权缺失漏洞给我最大的启示是在复杂的、可扩展的平台架构中权限校验的完整性极易在自定义扩展点或数据流转的边界处被破坏。作为开发者和架构师我们不能假设框架提供的每个“插槽”都是天生安全的。每一次实现一个扩展接口每一次从A点获取数据传递到B点都必须清晰地自问当前用户的权限上下文是否完整地、正确地传递到了每一个需要它的地方这次漏洞分析本质上是一次对数据流中权限上下文传递路径的追查之旅。在后续的所有Liferay项目中我都会把对InfoRequestContext的传递和利用作为代码审查清单里的必选项。