开源Newsletter系统多租户安全设计:MailCheap从账户隔离到API Key撤销全链路指南
【免费下载链接】mailcheapNewsletters where you pay for the emails you send, not for dormant subscribers, at a fraction of the price of beehiiv and the like. Open source: self-host it, or use mailcheap.ai.项目地址https://gitcode.com/gh_mirrors/mai/mailcheap点击查看免费下载MailCheap 是一个开源的 Newsletter邮件通讯系统你只为实际发出的邮件付费而不是为沉睡的订阅者付费价格仅为 beehiiv 等同类服务的一小部分。它支持自托管也可直接使用 mailcheap.ai。当一个平台承载成千上万个彼此独立的租户账户时Alice 绝不能碰到 Bob 的订阅者就成了一条生死线。本文完整拆解 MailCheap 的多租户安全设计从数据库层的账户隔离守卫、统一权限执行层到 API Key 的哈希存储、双级别权限与即时撤销并附带它每次发版都在跑的双账户渗透测试。为什么 Newsletter 系统必须做多租户隔离每个 Newsletter 作者都是一个租户他们的订阅者名单、草稿、发送历史、上传的图片、API Key 彼此必须完全隔离。一旦隔离失效后果是灾难性的——攻击者可以读取甚至删除别人的订阅者名单那可是受 GDPR 保护的个人信息或者用别人的 Newsletter 发垃圾邮件毁掉共享的域名声誉。MailCheap 的做法不是在每个页面记住过滤一下而是把隔离下沉到数据库访问层任何绕过守卫的查询在代码层面根本不可能发出。账户隔离第一道防线查询必须携带账户 ID核心实现只有 54 行在 lib/account-scope.js 中。它通过一个 Mongoose 插件accountScoped完成三件事强制字段所有客户数据模型Contact、Campaign、Newsletter、ApiKey、Upload…自动带上必填且不可变的accountId字段查询守卫给find、findOne、updateMany、deleteOne、aggregate、bulkWrite等 12 种数据库操作全部挂上pre钩子过滤器里没有accountId的查询直接抛异常而不是返回空结果见 assertScopedfunction assertScoped(modelName, filter, options) { if (options?.crossAccount || isAccountId(filter?.accountId)) return; throw new Error(${modelName} query without an accountId); }显式豁免Webhook、签名链接这类按唯一键找文档的场景必须显式声明{ crossAccount: true }让每一次跨账户访问在代码里都有名有姓。这个设计有个心理学上的妙处它把忘了写过滤条件从一个静默的越权漏洞变成了一个立即崩溃的运行时错误——忘写比写错安全得多。统一执行层三条入口一套检查MailCheap 的仪表盘、REST API 和 MCP 服务共享同一个执行器 lib/actions/run-action.js。所有功能都先注册成标准 action用 zod 描述输入输出再由runAction统一走完同样的检查流水线检查顺序内容拦截什么1账户是否处于删除等待期已删除账户的一切调用2API Key 级别是否够signups级 Key 调用full级操作3账户是否被封禁垃圾信号触发的封禁4订阅计划是否有效无付费计划的写操作5限流按 Key、按账户刷接口、滥用6输入校验zod畸形数据这意味着同一段安全规则不会因为入口不同而有缝隙网页上能做的事、API 上不能做或者反过来。项目甚至有一条测试如果仪表盘的 server action 绕过了注册 action 体系直接操作数据库测试就失败。API Key 全生命周期哈希存储、双级别、即时撤销这是 MailCheap 安全设计中教科书级的部分代码见 lib/api-key-tokens.js 与 lib/actions/api-keys.js。生成与存储。Key 是mc_前缀加 32 字节密码学随机数generateApiKey数据库里只存 SHA-256 哈希——即使整库泄露攻击者拿到的也是一堆不可逆的摘要无法冒充任何租户。明文 Key 只在创建时返回一次之后再也无法查看列表页只显示前缀mc_a1b2c3…供辨认models/ApiKey.js。双级别权限。Key 分full和signups两级full可执行所有操作但只能存在于服务器端signups只能新增订阅者专门留给嵌入网站代码的 Key。配合一条精妙的 CORS 规则所有端点中只有订阅接口对浏览器开放跨域lib/api/rest.js。也就是说就算有人手滑把fullKey 写进了前端页面浏览器里的恶意脚本也调不动它——CORS 会先拦下来。此外每个账户最多 20 个活跃 Key每个 Key 限 300 请求/分钟。撤销即生效。撤销操作revoke_api_key只是给记录打上revokedAt时间戳而鉴权查询authenticateRequest永远带revokedAt: null条件——下一个请求到达时该 Key 就自动失效无需遍历任何缓存或调用任何服务。Key 甚至可以撤销自己操作幂等被封禁的账户也允许撤销 Key止损永远优先。登录与会话一个验证码不能两用MailCheap 基于 Better Auth 构建lib/auth.js几个值得借鉴的细节会话存数据库而非纯 JWT登出或吊销立即生效不存在JWT 还没过期的窗口期验证码分型登录码和删除账户专用码是两种不同的 OTP 类型登录码删不了账户删除码也登不进系统验证码 6 位、5 分钟过期、3 次试错作废、存储时哈希自托管白名单私有部署只放行ALLOWED_EMAILS中的邮箱且在用户创建钩子和会话创建钩子双重拦截refuseUnlessAllowed——任何人被移出白名单下一个请求就会被签出他的 API Key 同步失效防批量注册云版限制同一 IP 每天最多 3 个新账户一次性邮箱域名直接拒绝且拒绝发生在验证码证明邮箱归属之后不会向攻击者泄露这个邮箱已注册。删除账户的完整链条立即冻结、30 天后清除删除账户lib/account-deletion.js是整条链路里体现纵深防御最好的环节只有属主本人能删——它刻意不被注册成 action所以 API Key 和已授权的第三方应用无法替你删除账户需要输入专用验证码 手打邮箱地址且 Stripe 仍在扣费、有发送中活动时拒绝删除请求一确认立即执行全部设备会话踢出signOutEverywhere、所有 API Key 撤销、已连接应用断开、邮件服务商处的租户挂起、账户在所有入口按未付费处理清除作业以签名的 QStash 任务形式提前发出30 天后执行期间重新登录可恢复账户一旦清除开始则不可逆restoreAccount清除作业里的每一条查询都带着accountId——清除一个租户绝不会误删隔壁的数据。每次发版都在跑的渗透测试这套设计最有力的证明是 tests/isolation.test.mjs测试创建 Bob 的完整世界Newsletter、订阅者、活动、API Key、上传文件然后让已登录的 Alice 用应用提供的所有通道去碰它server action改 Bob 的 Newsletter → { error: Newsletter not found } REST API用 Alice 的 Key 往 Bob 的列表加订阅者 → 404 守卫直测Contact.find({ email: reader1example.org }) → 抛异常 结果Bob 的数据快照前后完全一致一封测试邮件都没发出去注意两个安全细节越权尝试统一回答 not found 而非 forbidden不向攻击者泄露资源的存在性Alice 在过滤器里点名Bob 的 Newsletter 也查不到任何数据——因为accountId条件是守卫强制注入的业务代码想不小心泄露都难。上手体验 MailCheapMailCheap 采用 AGPL 开源协议git clone https://gitcode.com/gh_mirrors/mai/mailcheap后按仓库内配置文档即可自托管。自托管模式下没有计费墙但多租户隔离、Key 撤销、封禁与删除链条完整保留——你可以直接跑一遍隔离测试亲眼看着 Alice 的每一次越权尝试都被拦下。如果你想给自己的 Newsletter 平台做安全设计MailCheap 给出的公式可以抄作业隔离规则写在数据访问层用抛异常而非返回空所有入口Web、API、第三方应用共享同一个权限执行器凭证只存哈希、明文只见一次、撤销是无状态立即生效的用双账户对抗测试把越权变成 CI 里的一个断言。更多细节可参考仓库的安全说明 SECURITY.md 与隔离测试 tests/isolation.test.mjs。赞分享【免费下载链接】mailcheapNewsletters where you pay for the emails you send, not for dormant subscribers, at a fraction of the price of beehiiv and the like. Open source: self-host it, or use mailcheap.ai.项目地址https://gitcode.com/gh_mirrors/mai/mailcheap点击查看免费下载相关推荐Chorus安全设计详解OIDC登录、API Key管理与多租户数据隔离Chorus安全设计详解OIDC登录、API Key管理与多租户数据隔离 Chorus 是一款面向 AI 与人类协作的 Agent Harness智能体协作抖音TikTok数据采集免费方案DouK-Downloader从下载到分析的完整上手指南抖音TikTok数据采集免费方案DouK Downloader从下载到分析的完整上手指南 你有没有遇到过这种时刻刷到一个创作者作品全是你喜欢的风格想把他网页爬虫CLI短视频Cortex 读路径 Shuffle Sharding 设计解析从写路径 subring 到全链路租户隔离Cortex 读路径 Shuffle Sharding 设计解析从写路径 subring 到全链路租户隔离 Cortex README.md https:/可观测性时序数据库后端指标监控上一篇vanilla-extract的开源项目健康度项目维护状态下一篇CANN ops-nn 中 Logit 算子深度解析从数学原理到 aclnn 两段式调用实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

为什么Swift-Qwen3.8-27B推理快1.95倍?深入解析UkisAI“推理标记token惩罚“的防过度思考训练法

为什么Swift-Qwen3.8-27B推理快1.95倍?深入解析UkisAI“推理标记token惩罚“的防过度思考训练法

大模型推理模型本地部署多模态 【免费下载链接】Swift-Qwen3.8-27B-GGUF 项目地址: https://ai.gitcode.com/hf_mirrors/ukisai/Swift-Qwen3.8-27B-GGUF 点击查看 免费下载 Swift-Qwen3.8-27B 是 UkisAI 推出的 Qwen3.8-27B 推理加速衍生模型:通过"推理标记 t…

2026/10/18 2:58:05 阅读更多 →
G-Helper充电上限重启后不生效?先查配置和开机任务

G-Helper充电上限重启后不生效?先查配置和开机任务

G-Helper充电上限重启后不生效?先查配置和开机任务 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Exper…

2026/10/18 2:58:05 阅读更多 →
用LocalClaw搭建多Agent协作系统:架构、代码与踩坑记录

用LocalClaw搭建多Agent协作系统:架构、代码与踩坑记录

先说结论:这两年只要聊到AI应用,十个技术方案里八个在谈Agent。但大多数人做的Agent其实是个"单机版"——一个能调用工具、能回答问题的对话机器人,离真正的"协作系统"还差得远。我最近用LocalClaw重新搭了一套多Agent协…

2026/10/18 2:58:05 阅读更多 →

最新新闻

AI Agent与低代码融合:虚拟工作流平台的组件化架构实践

AI Agent与低代码融合:虚拟工作流平台的组件化架构实践

从去年年底开始,我在内部推进了一个结合AI能力与低代码开发的平台项目,代号"某协作工场"。核心目标很直接:让业务人员用自然语言描述需求,系统自动推荐并组装出可运行的工作流应用,同时将重复性的"虚拟…

2026/10/18 3:38:18 阅读更多 →
Vertex AI模型接入实战:Gemini 3与Veo 3.1全流程解析

Vertex AI模型接入实战:Gemini 3与Veo 3.1全流程解析

把 Gemini 3 Pro、Gemini 3 Flash、Veo 3.1 这三个模型接到 GCP Vertex AI 上,听起来就是把 Key 配好、发个请求、拿回结果的三步走,但实际操作下来,我在认证方式、区域开关、异步任务这四处来回折腾,尤其在 Veo 3.1 视频生成上&a…

2026/10/18 3:38:18 阅读更多 →
网易云与QQ音乐LRC歌词一键提取:单曲、批量、双语歌词全支持

网易云与QQ音乐LRC歌词一键提取:单曲、批量、双语歌词全支持

网易云与QQ音乐LRC歌词一键提取:单曲、批量、双语歌词全支持 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 163MusicLyrics 是一款云音乐歌词获取工具&#…

2026/10/18 3:38:18 阅读更多 →
半导体车间防静电门禁系统的数据追溯方案与实践

半导体车间防静电门禁系统的数据追溯方案与实践

半导体车间里,静电从来不是“小事”。干这行久了你会发现,一条看似不起眼的防静电门禁,背后牵扯的却是良率、客诉、甚至产品批次追责的大问题。晶圆被静电击穿往往悄无声息,等你从终测数据里发现问题时,已经说不清是哪…

2026/10/18 3:38:18 阅读更多 →
从CNN训练到PyQt5落地:花卉识别GUI分类工具开发全记录

从CNN训练到PyQt5落地:花卉识别GUI分类工具开发全记录

1. 项目背景与整体设计思路1.1 从命令行到GUI,这个版本解决了什么问题如果你看过我这个系列的第一篇,应该记得最初版本是一个纯命令行工具:把图片路径传进去,跑完CNN模型,终端里打印一行预测结果。能用,但说…

2026/10/18 3:38:18 阅读更多 →
从生物神经元到PyTorch:神经网络原理与训练实践

从生物神经元到PyTorch:神经网络原理与训练实践

最近总有人问我:入门深度学习,到底该先看什么?我的答案一直没变过——从大脑神经元到PyTorch,把神经网络这条主线一次跑通。神经网络不是高深莫测的黑魔法,它的设计灵感来自生物神经元,而今天你只需要几行P…

2026/10/18 3:37:18 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →