
Zulip 服务器安全加固实战指南从访问控制到限流与 SSRF 防护【免费下载链接】zulipZulip server and web application. Open-source team chat that helps teams stay productive and focused.项目地址: https://gitcode.com/GitHub_Trending/zu/zulip本篇指南系统讲解如何加固自托管 Zulip 服务器的安全性覆盖 shell 访问控制、SSO 认证、用户账户保护、权限模型、用户上传内容防护、出站请求 SSRF 防护以及内置限流系统六大主题。读完本文你将掌握 Zulip 官方推荐的安全基线能够正确配置RATE_LIMITING_RULES、Smokescreen 出站代理与文件上传后端等关键安全参数并理解其底层实现原理。1. 限制 shell 访问安全的第一道边界Zulip 安全模型中最重要的一条原则是任何对 Zulip 应用服务器或数据库服务器拥有 root 权限的人或者能够以应用服务器上zulip用户身份登录的人都拥有对整个 Zulip 安装实例及其全部数据的完全控制权——包括读取消息、修改聊天历史等操作。因此唯一安全的做法是只有少数完全可信的个人才能拥有服务器的 shell 访问权限。这既是运维纪律也是安全基线。在 Zulip 中所有服务均以zulip系统用户运行部署位于/home/zulip/deployments/目录下谁拿到zulip用户或 root 的 shell谁就等同于拿到了实例的万能钥匙。2. 优先使用单点登录SSO认证Zulip 推荐使用单点登录SSO作为首选登录方式例如 Google 认证、LDAP 等同时也支持密码认证。选择 SSO 的核心收益在于将身份验证委托给集中式的身份提供方IdP可以统一管理凭据生命周期、实施更严格的密码策略、降低本地密码库被攻破的风险。关于 Zulip 全部可用认证方式的详细配置参见 认证方式文档。Zulip 还支持 SAML、OIDC、GitHub 等社会化登录并在zproject/backends.py中实现了完整的认证后端体系管理员可在/etc/zulip/settings.py中按需启用。3. 教育用户保护自己的账户每个 Zulip 用户都拥有一个API key该 key 可以执行用户在登录状态下能做的几乎所有操作。这意味着一旦凭据泄露例如手机丢失或被盗攻击者就可以用该用户的身份读取消息、发送消息、管理其能访问的资源。务必让用户知晓以下防护要点在凭据可能泄露时如手机丢失、设备被他人接触立即重置 API key 和密码不要将 API key 写入明文文件或分享给他人在公共设备上使用后及时退出登录。从源码层面看API key 由服务端为用户生成并持久化在UserProfile.api_key字段中Web 客户端与 API 客户端均通过它完成身份认证因此它的敏感程度与密码完全等价。4. 熟悉 Zulip 的访问管理模型Zulip 拥有细粒度的权限管理体系管理员应熟悉以下核心概念才能合理配置组织权限频道类型与权限Zulip 将传统流stream重命名为频道channel支持公开频道、私有频道、仅可发帖频道等类型每种类型对应不同的可见与发言权限用户角色包括所有者owner、管理员administrator、版主moderator、成员member和访客guest等层级权限逐级递减用户组可将用户聚合为组并在权限设置中引用组来批量授权消息编辑与删除限制可配置消息可编辑/可删除的时间窗口与角色范围机器人Bot概览机器人与用户共享类似的权限模型但行为受限创建权限可由管理员控制。这些权限约束在服务端均有对应的模型与检查逻辑相关模型位于 zerver/models权限判断逻辑分散在 zerver/actions 与 zerver/lib 中合理组合它们可以精确划定每个用户能看什么、能做什么。5. 用户上传内容与用户生成请求的安全Zulip 支持用户上传文件同时消息中还可以包含图片预览、网页预览等用户生成的内容。这一节是自托管安全配置中实操性最强、最需要动手的部分。5.1 将上传文件托管在与主服务器不同的域名上Zulip 上传的文件理想情况下应托管在与主 Zulip 服务器不同的域名例如zulip-user-content.example.com以防止各类同域攻击如通过同源策略利用上传内容执行脚本或窃取 Cookie。Zulip 原生支持两种上传后端后端配置项说明本地文件存储LOCAL_UPLOADS_DIR文件存放在 Zulip 服务器文件系统的指定目录中默认值见 default_settings.pyS3 存储S3_AUTH_UPLOADS_BUCKET/S3_AVATAR_BUCKET/S3_REGION文件存放在 Amazon S3或兼容 S3 的对象存储中两个后端均通过统一的抽象接口对外提供服务完整接口定义在zerver/lib/upload/__init__.py中其中get_upload_backend()返回当前生效的后端实例generate_message_upload_path()生成存储路径store_message_attachment()负责落盘upload_message_attachment()最终返回形如/user_uploads/{path_id}的访问路径。具体实现分别位于 zerver/lib/upload/local.py 与 zerver/lib/upload/s3.py如果需要新增后端实现同一接口即可。S3 相关配置项bucket、region、endpoint、存储类等在 default_settings.py 中有完整定义。5.2 长随机 URL 与访问控制校验无论使用哪种后端上传文件的访问 URL 都是长随机字符串这是抵御未授权访问的第一层防护未授权用户只有拿到别人分享的 URL 才能访问文件。当然任何已授权用户本可以直接下载文件再转发因此这种 URL 混淆本身已算相当有效的保护。更重要的是Zulip 对上传文件的每一次访问都会做访问控制校验——服务端会确认当前浏览器登录的 Zulip 账户确实收到过该文件。这有效防止了因意外分享 URL例如转发错过的消息邮件、Referer 头泄露而导致的受限文件泄露。5.3 使用 go-camo 图片代理保护隐私Zulip 支持使用 go-camo 图片代理来代理内联图片预览等可能被其他用户插入到消息流中的内容。这样做可以避免客户端直接向外部服务器发起请求抓取图片从而保护用户隐私外部服务器无法获知访问者的 IP 与浏览器信息。Camo 相关配置包括CAMO_URI代理服务地址见 default_settings.py以及从zulip-secrets.conf读取的camo_key见 computed_settings.py。5.4 内联图片预览控制默认情况下当消息中包含图片链接时Zulip 会在消息正文中内联展示图片预览。管理员可通过INLINE_IMAGE_PREVIEW设置控制此行为默认值为True见 default_settings.py网页预览与嵌入则由INLINE_URL_EMBED_PREVIEW控制默认同样为True。5.5 出站 HTTP 连接与 SSRF 防护Zulip 在多种场景下会向外部服务器发起出站 HTTP 连接出站 webhook 机器人其创建权限可以被限制消息中的内联图片预览默认启用但可关闭内联网页预览与嵌入需配置启用Twitter 消息预览需配置启用BigBlueButton、Constructor Groups、Nextcloud Talk 与 Zoom 的 API 请求需配置启用相关 URL 通过密钥配置读取见 default_settings.py移动推送通知需配置启用。其中前三个功能赋予了终端用户有限驱动 Zulip 服务器代为发起 HTTP 请求的能力。因此Zulip 将所有出站 HTTP 请求都路由经过 Smokescreen 代理以防止服务器被利用来对内网其他系统发起 SSRF服务端请求伪造攻击。Smokescreen 的默认配置会拒绝所有非公网 IP 地址的访问包括127.0.0.1。出站代理的详细配置方法见 deployment.md 中的 Customizing the outgoing HTTP proxy 小节默认行为Zulip 将出站 webhook、网页预览、移动推送等所有出站 HTTP/HTTPS 流量经由 SmokescreenHTTPCONNECT代理转发默认拒绝非公网 IP含127.0.0.1放行公网主机。放行内网主机如果确有内网出站 webhook例如http://10.17.17.17:80/需在/etc/zulip/zulip.conf中配置白名单然后以 root 身份运行/home/zulip/deployments/current/scripts/zulip-puppet-apply使配置生效[http_proxy] allow_addresses 10.17.17.17改用自定义代理在zulip.conf中配置代理地址与端口[http_proxy]的host/port再运行zulip-puppet-apply。若将host置空可完全禁用出站代理——官方明确不推荐这样做因为这会让攻击者有机会利用 Zulip 服务器访问内部资源。Camo 的代理行为Camo 图片代理默认不经过 Smokescreen因为它自带拒绝私有子网的逻辑可通过proxy.enable_for_camo覆盖此行为配置项见 system-configuration.md。多前端部署如需将 Smokescreen 安装到独立主机可在该主机上应用zulip::profile::smokescreenPuppet 类并在[http_proxy]中指向该主机。S3 特例默认情况下 S3 文件存储后端绕过 Smokescreen因为 S3 需要使用云厂商的元数据服务地址169.254.169.254会被 Smokescreen 拦截若使用的 S3 兼容存储需要经过代理可另行配置。6. 理解 Zulip 的内置限流系统Zulip 对登录尝试、所有 API 访问以及某些可能被滥用滥发的操作内置了限流。例如邮件确认流程本质上是允许向尚未与 Zulip 账户关联的邮箱发送邮件的限制用户触发此类邮件的能力可以防止恶意行为者向随机邮箱地址滥发确认邮件、损害服务器的垃圾邮件声誉。6.1 默认限流规则默认规则定义在 zproject/default_settings.py 的DEFAULT_RATE_LIMITING_RULES中规则会随产品演进而变化。当前主要规则如下规则键默认限流用途api_by_user60 秒内 200 次每个用户的总 API 请求数防止客户端造成不合理服务器负载api_by_ip60 秒内 100 次未认证 API 请求主要服务于公开访问选项按 IPv4 地址或 IPv6 /64 子网分桶api_by_remote_server60 秒内 1000 次移动推送通知服务对单个 Zulip 服务器的请求Zulip Cloud 设置对不使用自建推送服务的自托管实例无影响authenticate_by_username30 分钟内 5 次失败针对单一用户名的登录密码认证尝试次数LDAP、邮箱密码后端外部认证如 GitHub SSO不适用email_change_by_user每小时 2 封、每天 5 封单用户修改邮箱地址触发的邮件防止滥用发信攻击服务器垃圾邮件声誉password_reset_form_by_email每小时 2 封、每天 5 封单邮箱地址触发的密码重置邮件sends_email_by_ip每天 5 封按 IP 统计所有直接触发发信的请求通用反垃圾措施spectator_attachment_access_by_file每天每文件 1000 次未认证用户在 web-public 场景下对上传文件的访问防止把文件上传功能当文件分发滥用sends_email_by_remote_server每天 10 封zilencer 专用远程计费系统触发发信的请求demo_realm_creation_by_ip每天 10 次按 IP 限制演示组织创建数量防止滥用演示组织功能transfer_remote_server_registration_endpoint_by_ip每天 10 次按 IP 限制远程服务器注册转移请求此外ABSOLUTE_USAGE_LIMITS_BY_ENDPOINT见 default_settings.py为极少数端点定义了绝对使用上限目前仅用于verify_registration_transfer_challenge_ack_endpoint每天 30 次此类端点不需要像RATE_LIMITING_RULES那样精细的覆盖机制。6.2 底层实现GCRA 算法与 Redis从源码看Zulip 的限流基于GCRAGeneric Cell Rate Algorithm通用信元速率算法实现——这是一种漏桶leaky-bucket变体每个规则在 Redis 中保存一个 TAT理论到达时间值核心实现位于 zerver/lib/rate_limiter.py。限流实体通过RateLimitedObject抽象类统一建模主要有三类RateLimitedUser以用户ID:域名为 keyapi_by_user域还支持读取用户资料上的rate_limits字段做个性化覆盖见 rate_limiter.pyRateLimitedIPAddr以 IP 为 keyIPv6 地址按 /64 子网聚合分桶tor-exit-node特殊标记用于 TOR 场景见 rate_limiter.pyRateLimitedEndpoint针对端点的绝对限制key 为端点名见 rate_limiter.py。每次请求经过rate_limit_request()时若超出限制会抛出RateLimitedError并中断请求见 rate_limiter.py。类还提供了block_access()、unblock_access()、clear_history()等方法供运维手动干预。6.3 管理员如何查看与调整限流管理员可以随时查看当前生效的规则使用部署目录下的工具直接打印生效配置/home/zulip/deployments/current/scripts/get-django-setting RATE_LIMITING_RULES或者直接阅读 zproject/default_settings.py 中带注释的DEFAULT_RATE_LIMITING_RULES。在/etc/zulip/settings.py中可通过以下方式调整完全禁用限流将RATE_LIMITING设为False默认True见 default_settings.py。RATE_LIMITING_AUTHENTICATE单独控制认证尝试的限流。不建议在生产环境禁用。覆盖特定规则通过RATE_LIMITING_RULES默认空字典见 default_settings.py添加要覆盖的规则条目该字典会与默认规则合并。设置后建议再次运行get-django-setting RATE_LIMITING_RULES验证修改是否生效然后执行scripts/restart-server重启服务使新配置生效。聚合 TOR 出口节点将RATE_LIMIT_TOR_TOGETHER设为True即可把所有已知的 TOR 出口节点视为同一 IP 桶来限流默认False。由于 TOR 流量会分散在多个出口节点不开启此选项时TOR 可被用来绕过基于 IP 的限流。TOR 出口节点列表每小时重新拉取更新一次。6.4 清除用户的登录限流状态当某个用户触发了登录尝试的限流后管理员可以用管理命令清除其状态manage.py reset_authentication_attempt_count --username用户名该命令定义在 zerver/management/commands/reset_authentication_attempt_count.py 中支持-u/--username参数指定要重置的用户名不带参数运行时打印帮助信息。更多管理命令的使用方式参见 管理命令文档。7. 发现安全问题如何上报如果你认为自己发现了安全漏洞请尽快通过securityzulip.com联系 Zulip 安全团队以便团队及时修复并做出负责任的安全披露responsible disclosure。请勿在公开渠道披露未修复的漏洞细节。本文要点回顾自托管 Zulip 的安全加固可以归纳为四条主线——(1) 收紧信任边界shell 访问最小化、SSO 优先、用户凭据教育(2) 理解权限模型并正确配置组织权限(3) 隔离并保护用户上传内容独立域名、访问控制校验、go-camo 代理、INLINE_IMAGE_PREVIEW开关(4) 用 Smokescreen 防护 SSRF、用内置限流系统RATE_LIMITING_RULES、RATE_LIMIT_TOR_TOGETHER抵御滥用。以上所有配置均可在/etc/zulip/settings.py与/etc/zulip/zulip.conf中完成修改后记得用get-django-setting验证、用scripts/restart-server或scripts/zulip-puppet-apply应用生效。【免费下载链接】zulipZulip server and web application. Open-source team chat that helps teams stay productive and focused.项目地址: https://gitcode.com/GitHub_Trending/zu/zulip创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考