Files
open-im-server-deploy/docs/SuperGroup使用限制分析.md
kim.dev.6789 e50142a3b9 复制项目
2026-01-14 22:16:44 +08:00

6.8 KiB
Raw Permalink Blame History

SuperGroup (GroupType=1) 使用限制分析

一、核心问题

如果绕过创建限制,创建了 GroupType=1 (SuperGroup) 的群组,在使用上会有以下关键差异和潜在问题

二、关键差异点

2.1 消息验证逻辑差异 ⚠️ 重要

位置: internal/rpc/msg/verify.go:187-220

SuperGroup (GroupType=1) 的特殊处理

if groupInfo.GroupType == constant.SuperGroup {
    // SuperGroup 跳过大部分检查,但仍需检查文件权限
    if data.MsgData.ContentType == constant.File {
        // 只检查文件发送权限
    }
    return nil  // 直接返回,跳过后续所有检查
}

WorkingGroup (GroupType=2) 的完整验证

  • 检查用户是否在群内
  • 检查文件发送权限(群主/管理员/userType=1
  • 检查链接发送权限userType=1/群主/管理员可发送链接)
  • 检查二维码图片userType=0 普通成员不能发送包含二维码的图片)
  • 检查禁言状态MuteEndTime
  • 检查群组是否被禁言GroupStatusMuted

差异总结

检查项 SuperGroup WorkingGroup
文件发送权限 检查 检查
链接检测 跳过 检查
二维码检测 跳过 检查
禁言检查 跳过 检查
群组禁言检查 跳过 检查

⚠️ 风险

  • SuperGroup 可以发送包含链接的消息,即使 userType=0
  • SuperGroup 可以发送包含二维码的图片,即使 userType=0
  • SuperGroup 成员即使被禁言也可以发送消息
  • SuperGroup 即使群组被禁言,成员仍可发送消息

2.2 消息推送机制

位置: internal/push/push_handler.go:104-116

推送逻辑

switch msgFromMQ.MsgData.SessionType {
case constant.ReadGroupChatType:
    err = c.Push2Group(ctx, msgFromMQ.MsgData.GroupID, msgFromMQ.MsgData)
default:
    err = c.Push2User(ctx, pushUserIDList, msgFromMQ.MsgData)
}

关键发现

  • 推送逻辑不依赖 GroupType,而是依赖 SessionType
  • SessionType 是客户端发送消息时指定的,不是根据 GroupType 自动确定的
  • 如果客户端发送消息时 SessionType != ReadGroupChatType,会走 Push2User 而不是 Push2Group

⚠️ 潜在问题

  • 如果创建了 GroupType=1 的群组,但客户端发送消息时使用 SessionType=WriteGroupChatType值为2消息会按单聊方式推送可能导致推送逻辑异常
  • Push2GroupPush2User 的推送机制不同,可能影响消息分发

2.3 会话ID生成差异

位置: pkg/msgprocessor/conversation.go:68-97

会话ID生成规则

case constant.WriteGroupChatType:
    return "g_" + msg.GroupID  // 普通群聊
case constant.ReadGroupChatType:
    return "sg_" + msg.GroupID  // 超级群聊

差异

  • WriteGroupChatType (值为2): 会话ID前缀为 g_
  • ReadGroupChatType (值为3): 会话ID前缀为 sg_

⚠️ 潜在问题

  • 如果 GroupType=1 但使用 SessionType=WriteGroupChatType会话ID会是 g_xxx 而不是 sg_xxx
  • 这可能导致会话管理不一致

2.4 在线推送方法

位置: internal/push/onlinepusher.go:99

推送方法

  • 所有群聊消息(无论 GroupType都使用 SuperGroupOnlineBatchPushOneMsg 方法
  • 方法名虽然叫 "SuperGroup",但实际上所有群聊都使用这个方法

结论:推送方法本身不受 GroupType 影响,但推送逻辑受 SessionType 影响

三、使用限制和潜在错误

3.1 必须使用正确的 SessionType ⚠️ 关键

问题:如果创建了 GroupType=1 的群组,但发送消息时:

  • 使用 SessionType=WriteGroupChatType (值为2) → 会走 Push2User,推送逻辑可能异常
  • 必须使用 SessionType=ReadGroupChatType (值为3) → 会走 Push2Group,推送正常

建议:客户端发送消息时,需要根据群组的 GroupType 自动设置正确的 SessionType

  • GroupType=1 (SuperGroup) → SessionType=ReadGroupChatType (值为3)
  • GroupType=2 (WorkingGroup) → SessionType=WriteGroupChatType (值为2) 或 ReadGroupChatType (值为3)

3.2 权限检查缺失 ⚠️ 安全风险

SuperGroup 跳过的检查

  1. 链接检测:普通成员可以发送包含链接的消息
  2. 二维码检测:普通成员可以发送包含二维码的图片
  3. 禁言检查:被禁言的成员仍可发送消息
  4. 群组禁言检查:群组被禁言时,成员仍可发送消息

安全影响

  • 可能被用于发送恶意链接
  • 可能被用于发送包含二维码的垃圾信息
  • 禁言功能失效

3.3 会话管理不一致

问题

  • 如果 GroupType=1 但使用 SessionType=WriteGroupChatType会话ID会是 g_xxx
  • 如果使用 SessionType=ReadGroupChatType会话ID会是 sg_xxx
  • 这可能导致同一个群组产生不同的会话ID造成会话管理混乱

四、总结

4.1 主要差异

方面 SuperGroup (GroupType=1) WorkingGroup (GroupType=2)
消息验证 跳过大部分检查(链接、二维码、禁言) 完整验证
文件权限 检查(群主/管理员/userType=1 检查(群主/管理员/userType=1
推送机制 依赖 SessionType需使用 ReadGroupChatType 依赖 SessionType
会话ID 需使用 ReadGroupChatType 生成 sg_ 前缀 可使用 WriteGroupChatType 或 ReadGroupChatType

4.2 使用建议

如果允许创建 SuperGroup 类型的群组,需要:

  1. 客户端适配

    • 发送消息时,根据群组的 GroupType 自动设置正确的 SessionType
    • GroupType=1SessionType=ReadGroupChatType (值为3)
  2. 安全考虑

    • 明确 SuperGroup 跳过权限检查的设计意图
    • 如果需要安全控制,考虑在业务层或回调中实现
  3. 一致性

    • 确保所有使用 SuperGroup 的地方都使用 ReadGroupChatType
    • 统一会话ID生成规则

4.3 潜在错误场景

  1. 推送错误:如果使用错误的 SessionType消息可能无法正确推送给所有群成员
  2. 会话混乱同一个群组可能产生不同的会话ID
  3. 权限绕过SuperGroup 会跳过禁言等权限检查
  4. 安全风险:可以发送链接和二维码,可能被滥用

五、代码修改建议

如果要支持 SuperGroup建议

  1. 创建群组时:允许 GroupType=1GroupType=2
  2. 消息发送时:根据 GroupType 自动设置 SessionType
  3. 消息验证时:明确 SuperGroup 的特殊逻辑,考虑是否需要保留部分安全检查
  4. 文档说明:明确 SuperGroup 和 WorkingGroup 的差异和使用场景