Issue 1:GET /attachments/{attachmentId}
(对象级读取缺失检查候选,最终裁决:非漏洞)
1. 风险分析
该接口在读取附件时未显式校验 chat_attachment.user_id,理论上可能导致跨用户附件读取。一旦攻击者获取他人 attachmentId,可直接获取附件原始内容。
但该风险是否成立依赖于 ID 泄露面及系统整体访问模型,当前证据不足以证明可稳定利用。
2. 漏洞信息
-
接口:
GET /attachments/{attachmentId} -
候选问题:
(read, chat_attachment.user_id)(read, chat_attachment.data)
3. 核验细节
-
入口授权:
@AdminOrDeveloperAuth(仅校验身份类型)- 无对象归属校验
AttachmentController.java:44-58
-
Sink:
ChatAttachmentServiceImpl.getAttachmentDetail()- 直接按
attachmentId查询并返回data ChatAttachmentServiceImpl.java:104-123
-
Owner 字段存在:
- 上传时写入
chat_attachment.user_id ChatAttachmentServiceImpl.java:57-68
- 上传时写入
-
缺失点:
- 查询路径未使用
user_id进行约束
- 查询路径未使用
-
对照防线:
ChatSessionServiceImpl.findUserSession():绑定 user 查询ConsumerServiceImpl.findDevConsumer():绑定 user 查询- 附件路径缺少同类约束
4. 安全建议
(防御性优化建议)
-
查询时增加:
WHERE attachment_id = ? AND user_id = currentUserId -
若存在跨用户访问需求,应显式建模授权关系(如分享/引用)
-
增加访问日志,便于审计异常访问
Issue 2:GET /developers/oidc/callback
(高风险:跨 Portal 身份复用 / 租户隔离失效)
1. 风险分析
系统在 OIDC 登录回调中复用了全局外部身份(provider + subject),而未校验其所属 portalId。
这会导致攻击者在一个 Portal 的合法 developer 身份,被跨 Portal 复用,从而绕过注册审批和租户隔离。
最严重影响:
- 绕过 Portal 独立账号体系
- 未经审批访问敏感 API
- 在目标 Portal 中创建资源并订阅产品
2. 漏洞信息
-
接口:
GET /developers/oidc/callback -
问题类型:
(authenticate, developer.portal_id)
3. 核验细节
入口阶段
-
OidcServiceImpl.handleCallback()- 基于当前 portal 配置完成 OIDC 验证
OidcServiceImpl.java:96-123
Sink(关键问题)
-
createOrGetDeveloper()developerService.getExternalDeveloper(provider, subject) -
仅按 (provider, subject) 查找
-
未校验:
developer.portal_id == current_portal
相关代码:
DeveloperServiceImpl.java:202-207DeveloperExternalIdentity.java:27-33(唯一键不含 portalId)
Token 发放
TokenUtil.generateDeveloperToken(developerId)- JWT 不包含
portalId TokenUtil.java:95-106
后续生效点
-
业务逻辑中:
developerId来自 tokenportalId来自当前请求上下文
典型混写路径:
-
ConsumerServiceImpl.createConsumer()- 写入
(developerId=devA, portalId=portalB) ConsumerServiceImpl.java:101-121
- 写入
-
查询路径:
getPrimaryConsumer()仅按 developerIdConsumerServiceImpl.java:760-789
对照防线
-
内建账号登录:
(portalId + username)绑定DeveloperServiceImpl.java:104-130
-
外部身份登录:
- ❌ 缺少 portal 维度约束
4. 安全建议
核心修复点
在复用 developer 前强制校验:
developer.portalId == contextHolder.getPortal()
补充修复建议
-
唯一约束调整
(provider, subject, portalId) -
Token 绑定租户
- 在 JWT 中加入
portalId - 所有请求校验 token.portalId == 当前 portal
- 在 JWT 中加入
-
隔离策略
- 禁止跨 portal 复用 developer
- 或明确建模“多 portal 共享身份”
Issue 3:POST /developers/oauth2/token
(与 Issue 2 同根因:跨 Portal 身份复用)
1. 风险分析
OAuth2 JWT Bearer 登录路径与 OIDC 回调共享同一缺陷:
认证成功后复用全局 developer,而非按 portal 隔离,导致跨租户身份混用。
2. 漏洞信息
-
接口:
POST /developers/oauth2/token -
问题类型:
(authenticate, developer.portal_id)
3. 核验细节
-
OAuth2ServiceImpl.authenticate()- 校验 assertion(基于 portal 配置)
-
createOrGetDeveloper():- 同 Issue 2,复用全局 developer
-
关键缺失:
- 未校验 developer.portal_id
4. 安全建议
与 Issue 2 完全一致:
- 强制校验 portal 归属
- token 绑定 portalId
- 外部身份唯一键引入 portal 维度
总体结论
本组问题核心可抽象为:
跨租户身份绑定缺失(Cross-Tenant Identity Binding Failure)
模式特征
- 入口完成认证(OIDC / OAuth2)
- 外部身份映射为本地用户
- ❌ 未绑定租户(portalId)
- ❌ token 未携带租户信息
- ❌ 后续请求依赖“当前上下文”而非“登录上下文”
可抽象为检测规则
Source:external identity authentication (OIDC / OAuth2)Sink:local user lookup or creationMissing:tenant binding (portalId)Pattern:(provider, subject) → global userinstead of(provider, subject, tenant) → scoped user
