[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"portal-settings:stajic:zh":3,"public-menus:all":38,"post:rbac-vs-tenant-isolation-two-different-security-boundaries:zh":205,"related:post:rbac-vs-tenant-isolation-two-different-security-boundaries:zh:1":3037},{"statusCode":4,"data":5,"message":37},200,{"tenantId":6,"lang":7,"defaultLang":8,"siteUrl":9,"contactEmail":10,"brandName":11,"logoUrl":12,"siteName":11,"siteDescription":13,"ogImage":10,"robotsIndex":14,"socialLinks":10,"reservedSlugs":10,"seoPolicy":15},"stajic","zh","de","https:\u002F\u002Fstajic.de",null,"Stajic Platform","\u002FLogo_Planet.svg","Stajic Portal",true,{"branding":16,"relatedContent":17,"crossDomainLinks":18},{"logoUrl":12},{"enabled":14},[19,22,25,28,31,34],{"url":20,"label":21,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Ffigure.rocks","figure.rocks",{"url":23,"label":24,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Floving.rocks","loving.rocks",{"url":26,"label":27,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.com","bazify.com",{"url":29,"label":30,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.de","bazify.de",{"url":32,"label":33,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.at","bazify.at",{"url":35,"label":36,"isActive":14,"showInFooter":14,"includeInSameAs":14},"https:\u002F\u002Fbazify.ba","bazify.ba","Portal settings resolved",[39,45],{"id":40,"name":41,"location":42,"isActive":14,"isDefault":43,"items":44},1,"main-navigation","header",false,[],{"id":46,"name":47,"location":48,"isActive":14,"isDefault":14,"items":49},4,"main-menu","sidebar",[50,66,79,93,103,118,133],{"id":51,"title":52,"url":60,"target":61,"icon":62,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":64,"portfolioId":10,"children":65},"item-18",{"de":53,"en":54,"es":55,"fr":56,"it":54,"ru":57,"sr":58,"zh":59},"Startseite","Home","Inicio","Accueil","Главная","Почетна","首页","\u002Ffull-stack-web-developer-munich-performance-seo-and-maintainable-builds","_self","i-lucide-home","page",111,[],{"id":67,"title":68,"url":75,"target":61,"icon":76,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":77,"portfolioId":10,"children":78},"item-22",{"de":69,"en":69,"es":70,"fr":69,"it":71,"ru":72,"sr":73,"zh":74},"Vision","Visión","Visione","Видение","Визија","想象","\u002Fueber-uns-webdesign-muenchen-webaplikation","i-lucide-eye",113,[],{"id":80,"title":81,"url":89,"target":61,"icon":90,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":91,"portfolioId":10,"children":92},"item-19",{"de":82,"en":83,"es":84,"fr":83,"it":85,"ru":86,"sr":87,"zh":88},"Leistungen","Services","Servicios","Servizi","Услуги","Услуге","服务","\u002Fservices-dienstleistungen-muenchen","i-lucide-wrench",116,[],{"id":94,"title":95,"url":99,"target":61,"icon":100,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":101,"portfolioId":10,"children":102},"item-23",{"de":96,"en":96,"es":96,"fr":96,"it":96,"ru":97,"sr":97,"zh":98},"Blog","Блог","博客","\u002Fblog","i-lucide-book-open",112,[],{"id":104,"title":105,"url":114,"target":61,"icon":115,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":116,"portfolioId":10,"children":117},"item-32",{"de":106,"en":107,"es":108,"fr":109,"it":110,"ru":111,"sr":112,"zh":113},"Neue Technologien","New Technologies","Nuevas tecnologías","Nouvelles technologies","Nuove tecnologie","Новые технологии","Нове технологије","新技术！","\u002Fneue-webtechnologien","i-lucide-sparkles",122,[],{"id":119,"title":120,"url":129,"target":61,"icon":130,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":131,"portfolioId":10,"children":132},"item-20",{"de":121,"en":122,"es":123,"fr":124,"it":125,"ru":126,"sr":127,"zh":128},"Kontakt","Contact us!","Contacto","Contact","Contatto","Контакт","Контактирајте нас","联系我们！","\u002Fcontact","i-lucide-mail",115,[],{"id":134,"title":135,"url":144,"target":61,"icon":145,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":146,"portfolioId":10,"children":147},"item-21",{"de":136,"en":137,"es":138,"fr":139,"it":140,"ru":141,"sr":142,"zh":143},"Unsere Arbeit","Our Work","Nuestro trabajo","Nos réalisations","I nostri lavori","Наши работы","Наши радови","文件夹","\u002Fportfolio","i-lucide-briefcase",114,[148,161,175,181,193],{"id":149,"title":150,"url":144,"target":61,"icon":159,"isActive":14,"type":63,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":146,"portfolioId":10,"children":160},"item-24",{"de":151,"en":152,"es":153,"fr":154,"it":155,"ru":156,"sr":157,"zh":158},"Alle Projekte","All Projects","Todos los proyectos","Tous les projets","Tutti i progetti","Все проекты","Сви пројекти","所有项目","i-lucide-grid-3x3",[],{"id":162,"title":163,"url":171,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":174},"item-29",{"de":164,"en":165,"es":166,"fr":167,"it":168,"ru":169,"sr":170,"zh":143},"Local Roots, Global Reach","Local Roots - Global Reach","Empresa local ","Entreprise locale","Azienda locale","Местная компания","Локално предузеће глобално тржиште","\u002Fportfolio\u002Flocal-roots-global-reach-communication-media-systems-for-modern-business","i-lucide-folder","custom",[],{"id":176,"title":177,"url":179,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":180},"item-28",{"de":178,"en":178,"es":178,"fr":178,"it":178,"ru":178,"sr":178,"zh":178},"Solr Suggester","\u002Fportfolio\u002Fsolr-fuzzy-suggester-und-solr-infix-suggester-abfrage-ueber-ajax-und-filterung",[],{"id":182,"title":183,"url":191,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":192},"item-27",{"de":184,"en":185,"es":186,"fr":187,"it":188,"ru":189,"sr":190,"zh":185},"Firmenwebseite SEO","Company Website SEO","Sitio web corporativo SEO","Site web d’entreprise SEO","Sito web aziendale SEO","Корпоративный сайт SEO","Пословна веб-страница SEO","\u002Fportfolio\u002Fseo-sem-branding-mobile-webseite-muenchen",[],{"id":194,"title":195,"url":203,"target":61,"icon":172,"isActive":14,"type":173,"productId":10,"categoryId":10,"shopCategoryId":10,"articleId":10,"pageId":10,"portfolioId":10,"children":204},"item-31",{"de":196,"en":197,"es":198,"fr":199,"it":200,"ru":201,"sr":202,"zh":197},"Digitalisierungsportal","Digitalization Portal","Portal de digitalización","Portail de numérisation","Portale di digitalizzazione","Портал цифровизации","Портал за дигитализацију","\u002Fportfolio\u002Fdigitalisierungsportal-archiv-museum-bibliothek-ead-lido-mets-mods",[],{"statusCode":4,"data":206,"message":3036},{"id":207,"title":208,"slug":209,"content":210,"contentJson":211,"excerpt":1411,"featuredImage":1412,"featuredImageAlt":1413,"featuredImageCaption":10,"featuredImageTitle":10,"featuredImageCopyright":10,"featuredImageAuthor":10,"featuredImageSourceUrl":10,"featuredImageLicense":10,"featuredImageIsAiGenerated":43,"status":1414,"publishedAt":1415,"createdAt":1416,"updatedAt":1417,"seoLocalePaths":1418,"categories":1427,"author":1440,"translations":1445},"490","RBAC与租户隔离：两种不同的安全边界","rbac-vs-tenant-isolation-two-different-security-boundaries","\u003Cp>RBAC 和租户隔离解决了多租户系统中两个不同的安全问题。基于角色的访问控制（RBAC）决定已认证主体被允许做什么，例如读取订单、编辑产品或管理用户。租户隔离决定该主体被允许访问哪个租户的数据、资源和执行上下文。一个用户可能被正确认证并正确分配了 RBAC 角色，但如果应用程序允许该角色操作另一个租户的资源，仍然会遭遇安全失败。\u003C\u002Fp>\n\u003Caside class=\"editorjs-callout editorjs-callout--info my-6 rounded-xl border p-5 border-blue-300 bg-blue-50 dark:border-blue-900 dark:bg-blue-950\u002F20\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">直接回答\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">\u003Cstrong>RBAC 回答“这个身份可以做什么？”租户隔离回答“它可以在谁的边界内做这件事？”\u003C\u002Fstrong>\u003Cbr>\u003Cbr>安全的多租户应用程序通常需要两者兼备。租户管理员可能拥有广泛的权限，但这些权限应保持在管理员所属租户的范围内，除非存在明确独立的平台级权限。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Caside class=\"editorjs-callout editorjs-callout--warning my-6 rounded-xl border p-5 border-amber-300 bg-amber-50 dark:border-amber-900 dark:bg-amber-950\u002F20\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">角色不是租户边界\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">给用户分配 \u003Ccode>ADMIN\u003C\u002Fcode> 角色并不自动意味着“仅限租户 A 的管理员”。该角色必须与已验证的租户上下文以及目标资源的租户所有权一起评估。否则，一个有效的角色可能变成跨租户权限。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Caside class=\"editorjs-callout editorjs-callout--note my-6 rounded-xl border p-5 border-gray-300 bg-gray-50 dark:border-gray-700 dark:bg-gray-900\u002F40\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">当前来源说明 — 2026 年 10 月 8 日\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">底层区别是稳定的。NIST 围绕用户、角色、权限、操作和对象来定义 RBAC。当前 AWS SaaS 指南明确指出，身份验证和授权并不等同于租户隔离，并且如果未单独强制执行隔离，用户即使已通过身份验证和授权，仍可能访问另一个租户的资源。OWASP 当前的多租户安全指南同样将租户隔离视为一项跨层要求，涵盖 API、数据库、缓存、存储、队列和其他共享资源。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Cnav class=\"editorjs-toc\" data-editorjs-toc=\"true\" aria-label=\"目录\">\u003Cstrong class=\"editorjs-toc__title\">目录\u003C\u002Fstrong>\u003Col class=\"editorjs-toc__list editorjs-toc__list--depth-0\">\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-6\" class=\"editorjs-toc__link\">RBAC 真正控制什么\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-10\" class=\"editorjs-toc__link\">租户隔离真正控制什么\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-14\" class=\"editorjs-toc__link\">最简单的例子\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-19\" class=\"editorjs-toc__link\">简单示例的局限\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-23\" class=\"editorjs-toc__link\">RBAC 与租户隔离\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-25\" class=\"editorjs-toc__link\">认证、授权和隔离是三种不同的检查\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-28\" class=\"editorjs-toc__link\">角色需要作用域\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-32\" class=\"editorjs-toc__link\">租户上下文必须来自可信路径\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-36\" class=\"editorjs-toc__link\">租户作用域应属于资源查找的一部分\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-40\" class=\"editorjs-toc__link\">应用检查有用，但隔离不应依赖于完美的开发者行为\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-44\" class=\"editorjs-toc__link\">数据库隔离策略\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-47\" class=\"editorjs-toc__link\">PostgreSQL 行级安全可以提供纵深防御\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-51\" class=\"editorjs-toc__link\">租户隔离必须包括缓存\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-55\" class=\"editorjs-toc__link\">文件和对象存储需要自己的租户边界\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-59\" class=\"editorjs-toc__link\">后台任务和队列可能破坏隔离\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-63\" class=\"editorjs-toc__link\">搜索和 RAG 需要租户感知的检索\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-68\" class=\"editorjs-toc__link\">派生数据继承租户敏感性\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-71\" class=\"editorjs-toc__link\">并非所有内容都属于某个租户\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-75\" class=\"editorjs-toc__link\">平台管理员需要不同的权限模型\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-79\" class=\"editorjs-toc__link\">RBAC 可以与属性结合使用\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-83\" class=\"editorjs-toc__link\">授权决策至少是二维的\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-85\" class=\"editorjs-toc__link\">原始实现证据：Aaasaasa AI CMS\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-94\" class=\"editorjs-toc__link\">为什么这一区分对 AI 代理更为重要\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-98\" class=\"editorjs-toc__link\">分别测试 RBAC 和租户隔离\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-101\" class=\"editorjs-toc__link\">常见故障模式\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-103\" class=\"editorjs-toc__link\">常见误解\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-105\" class=\"editorjs-toc__link\">实用的设计顺序\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-107\" class=\"editorjs-toc__link\">RBAC + 租户隔离检查清单\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-109\" class=\"editorjs-toc__link\">边界情况与限制\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-115\" class=\"editorjs-toc__link\">什么会改变这个答案？\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-119\" class=\"editorjs-toc__link\">相关规范知识\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-125\" class=\"editorjs-toc__link\">常见问题\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-127\" class=\"editorjs-toc__link\">术语表\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-129\" class=\"editorjs-toc__link\">结论\u003C\u002Fa>\u003C\u002Fli>\u003Cli class=\"editorjs-toc__item\">\u003Ca href=\"#section-133\" class=\"editorjs-toc__link\">主要来源和当前指南\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Fol>\u003C\u002Fnav>\n\u003Ch2 id=\"section-6\">RBAC 真正控制什么\u003C\u002Fh2>\n\u003Cp>RBAC 是一种授权模型，其中权限与角色关联，用户被分配到这些角色。角色充当身份与权限之间的管理抽象。\u003C\u002Fp>\n\u003Cp>NIST 经典的 RBAC 工作围绕用户、角色、权限、操作和对象将其形式化。实际好处是，组织可以通过相对稳定的工作或职责角色来管理授权，而不是将每个权限直接附加到每个用户。\u003C\u002Fp>\n\u003Cp>例如，EDITOR 这样的角色可以表示：可以读取内容、写入内容和发布内容。ACCOUNTANT 这样的角色可以表示：可以读取账单数据、核对发票和批准结算。\u003C\u002Fp>\n\u003Ch2 id=\"section-10\">租户隔离真正控制什么\u003C\u002Fh2>\n\u003Cp>租户隔离是一组机制，用于防止一个租户在共享系统中读取、修改、影响或意外接收另一个租户的资源。\u003C\u002Fp>\n\u003Cp>受保护的边界比数据库行更广泛。租户特定状态可能存在于关系表、对象存储、向量索引、缓存、搜索索引、队列消息、文件、临时产物、后台作业、分析、速率限制和基础设施资源中。\u003C\u002Fp>\n\u003Cp>AWS 的 SaaS 指南明确指出了这一区别：授权授予对资源的访问权限，而租户隔离确保即使基础设施是共享的，这些资源也不会跨越错误的租户边界。\u003C\u002Fp>\n\u003Ch2 id=\"section-14\">最简单的例子\u003C\u002Fh2>\n\u003Cp>假设 Alice 是租户 A 的管理员，Bob 是租户 B 的管理员。两个用户都合法地拥有相同的 ADMIN 角色。\u003C\u002Fp>\n\u003Cp>RBAC 可以正确判断两个用户都可以执行诸如 users.read 之类的操作。但当 Alice 请求用户 ID 847 时，应用程序仍必须验证用户 847 属于租户 A。\u003C\u002Fp>\n\u003Cp>如果 API 只检查“Alice 拥有 ADMIN”，然后执行 SELECT * FROM users WHERE id = 847，那么 RBAC 成功了，而租户隔离失败了。\u003C\u002Fp>\n\u003Csection class=\"editorjs-process my-6\">\u003Ch3 class=\"mb-3 text-lg font-semibold\">正确的多租户授权决策\u003C\u002Fh3>\u003Cdiv class=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">1\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">1. 认证主体\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">确定用户、服务或代理是谁。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">2\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">2. 解析已验证的租户上下文\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">从可信的服务器端身份\u002F成员信息中确定适用哪个租户上下文。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">3\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">3. 解析权限\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">评估主体的角色或策略是否允许所请求的操作。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">4\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">4. 限定目标资源范围\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">验证目标对象属于允许的租户或明确共享的范围。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">5\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">5. 在访问边界强制执行\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">在应用租户约束的情况下执行数据库、缓存、存储、队列或服务操作。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">6\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">6. 审计两个维度\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">记录主体、租户、操作、目标和结果，以便跨租户尝试可见。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fsection>\n\u003Ch2 id=\"section-19\">简单示例的局限\u003C\u002Fh2>\n\u003Cp>真实系统通常包含多种身份类别：租户用户、平台管理员、后台工作进程、集成、代理以及跨租户运营服务。其中一些身份合法地跨越租户边界。\u003C\u002Fp>\n\u003Cp>这并不消除隔离的必要性。它意味着跨租户权限必须是显式的、狭窄的且可单独审计的，而不是从全局角色或无范围限制的数据库连接中意外产生的。\u003C\u002Fp>\n\u003Cp>租户隔离也可能因层而异。一个产品可能共享应用服务器但分离数据库，或者使用带有行级策略的共享数据库，同时为高级租户提供隔离的存储或计算资源。不存在单一的通用隔离拓扑。\u003C\u002Fp>\n\u003Ch2 id=\"section-23\">RBAC 与租户隔离\u003C\u002Fh2>\n\u003Csection class=\"editorjs-comparison my-6\">\u003Ch3 class=\"mb-3 text-lg font-semibold\">两个不同的安全维度\u003C\u002Fh3>\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 bg-gray-50 px-4 py-3 text-left dark:border-gray-700 dark:bg-gray-900\">\u003C\u002Fth>\u003Cth class=\"border border-gray-300 bg-gray-50 px-4 py-3 text-left font-semibold dark:border-gray-700 dark:bg-gray-900\">RBAC\u003C\u002Fth>\u003Cth class=\"border border-gray-300 bg-gray-50 px-4 py-3 text-left font-semibold dark:border-gray-700 dark:bg-gray-900\">租户隔离\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-3 text-left font-semibold dark:border-gray-700\">主要问题\u003C\u002Fth>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-3 text-left font-semibold dark:border-gray-700\">典型单元\u003C\u002Fth>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-3 text-left font-semibold dark:border-gray-700\">示例\u003C\u002Fth>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-3 text-left font-semibold dark:border-gray-700\">典型故障\u003C\u002Fth>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-3 text-left font-semibold dark:border-gray-700\">典型实现\u003C\u002Fth>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-3 text-left font-semibold dark:border-gray-700\">能否单独存在？\u003C\u002Fth>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-3 dark:border-gray-700\">\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\u003C\u002Fsection>\n\u003Ch2 id=\"section-25\">认证、授权和隔离是三种不同的检查\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">层\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">问题\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">示例故障\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">认证\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">这个主体是谁？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">攻击者冒充 Alice\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">授权 \u002F RBAC\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">这个主体可以执行此操作吗？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">查看者可以删除用户\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户隔离\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">此操作可以触及此租户\u002F资源边界吗？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户 A 管理员读取租户 B 的订单\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>这些检查相互关联但不可替代。认证可以完美无缺，而授权却失败。授权可以正确无误，而租户隔离却失败。安全的 SaaS 请求路径需要所有适用的边界。\u003C\u002Fp>\n\u003Ch2 id=\"section-28\">角色需要作用域\u003C\u002Fh2>\n\u003Cp>没有作用域，ADMIN 这个词是不完整的。它可以指平台管理员、租户管理员、项目管理员、工作区管理员或某个子系统的管理员。\u003C\u002Fp>\n\u003Cp>在多租户系统中，角色分配通常应与租户成员资格或其他显式资源作用域相关联。同一用户可以在租户 A 中合法地是 ADMIN，而在租户 B 中是 VIEWER。\u003C\u002Fp>\n\u003Cp>忽略这种区别的全局角色模型，即使权限映射本身是正确的，也可能造成权限泄漏。\u003C\u002Fp>\n\u003Ch2 id=\"section-32\">租户上下文必须来自可信路径\u003C\u002Fh2>\n\u003Cp>客户端提供的租户 ID 作为选择器是有用的，但它不是权限的证明。服务器必须根据已认证的身份和当前授权数据来推导或验证租户成员资格。\u003C\u002Fp>\n\u003Cp>OWASP 当前的多租户指南建议在请求生命周期的早期建立租户上下文，并明确警告不要将客户端标头或请求参数视为授权证明。\u003C\u002Fp>\n\u003Cp>这一点很重要，因为从 tenant=A 到 tenant=B 的简单请求修改不应足以跨越隔离边界。\u003C\u002Fp>\n\u003Ch2 id=\"section-36\">租户作用域应属于资源查找的一部分\u003C\u002Fh2>\n\u003Cp>一种常见的应用层隔离模式是在解析资源的同一个查询中包含租户范围。\u003C\u002Fp>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">弱查找\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">更强的租户范围查找\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">findFirst({ where: { id } })\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">findFirst({ where: { id, tenantId } })\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">UPDATE orders SET ... WHERE id = ?\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">UPDATE orders SET ... WHERE id = ? AND tenant_id = ?\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">cache.get('user:' + id)\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">cache.get('tenant:' + tenantId + ':user:' + id)\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>这种模式不是唯一可能的隔离机制，但它使租户所有权贴近数据访问操作，并防止对象 ID 成为跨租户能力。\u003C\u002Fp>\n\u003Ch2 id=\"section-40\">应用检查有用，但隔离不应依赖于完美的开发者行为\u003C\u002Fh2>\n\u003Cp>AWS 的隔离指南明确警告不要将隔离执行仅留给服务开发者。在大型代码库中，最终可能有一个查询、缓存键或工作路径会遗漏租户范围。\u003C\u002Fp>\n\u003Cp>因此，纵深防御可以将隔离移至共享中间件、仓库\u002F服务层、策略引擎、数据库行级安全、专用凭据、独立模式或独立数据库，具体取决于风险和架构。\u003C\u002Fp>\n\u003Caside class=\"editorjs-callout editorjs-callout--success my-6 rounded-xl border p-5 border-emerald-300 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950\u002F20\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">隔离应该难以被遗忘\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">最强的边界是普通应用代码无法通过省略一个 \u003Ccode>tenantId\u003C\u002Fcode> 条件而随意绕过。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Ch2 id=\"section-44\">数据库隔离策略\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">策略\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">边界\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">强度 \u002F 权衡\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">共享表 + 租户键\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">行\u002F应用策略\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">操作高效；需要详尽的租户范围和强测试\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">共享表 + 数据库 RLS\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">数据库策略边界\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">减少对每个应用查询的依赖；需要正确的角色、会话\u002F事务租户上下文和策略覆盖\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">独立模式\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">命名空间 \u002F 数据库角色边界\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">更强的逻辑分离；更多的操作复杂性\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">独立数据库\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">数据库 \u002F 凭据边界\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">强隔离和更简单的爆炸半径故事；更高的配置和操作成本\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">独立基础设施\u002F账户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">基础设施边界\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">最强的粗粒度分离；最高的成本和操作开销\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">混合\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">按工作负载\u002F数据类别\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">仅在风险\u002F合规性证明合理时允许更强的隔离\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>OWASP 当前的多租户安全备忘单列出了独立数据库、独立模式、带行级控制的共享表和混合模型。正确的模型取决于威胁级别、合规性、性能和操作成本。\u003C\u002Fp>\n\u003Ch2 id=\"section-47\">PostgreSQL 行级安全可以提供纵深防御\u003C\u002Fh2>\n\u003Cp>对于共享表，PostgreSQL 行级安全可以在数据库层强制执行租户谓词，以便普通查询无法看到活动租户策略之外的行。\u003C\u002Fp>\n\u003Cp>然而，RLS 不是魔法。PostgreSQL 超级用户和具有 BYPASSRLS 的角色可以绕过行策略。因此，OWASP 建议使用最小权限的请求路径角色，并测试生产环境中使用的相同连接\u002F池化模式。\u003C\u002Fp>\n\u003Cp>连接重用是另一个重要的边缘情况：必须为每个事务\u002F请求安全地设置和重置租户上下文，以便一个池化连接不会泄漏先前的租户状态。\u003C\u002Fp>\n\u003Ch2 id=\"section-51\">租户隔离必须包括缓存\u003C\u002Fh2>\n\u003Cp>数据库查询可以完美地限定范围，但仍然通过共享缓存键泄漏数据。\u003C\u002Fp>\n\u003Cp>如果 user:42 同时存在于租户 A 和租户 B 中，全局缓存键可能会返回错误租户的值。租户敏感的缓存键应包含每个改变可见性或结果语义的属性，通常是租户、用户、区域设置、功能集或权限版本。\u003C\u002Fp>\n\u003Cp>缓存分区是纵深防御，而不是授权的替代品。在返回受保护的缓存内容之前，请求仍然需要被授权。\u003C\u002Fp>\n\u003Ch2 id=\"section-55\">文件和对象存储需要自己的租户边界\u003C\u002Fh2>\n\u003Cp>对象存储应区分全局对象、租户范围对象和用户范围对象。除非访问策略实际约束了读写，否则仅靠文件夹前缀只是一种命名约定。\u003C\u002Fp>\n\u003Cp>当风险或合规要求更强的隔离时，更稳健的设计可以使用租户感知的对象键、存储桶策略、独立的存储桶\u002F账户或租户特定的加密密钥。\u003C\u002Fp>\n\u003Cp>签名 URL 必须在签发前获得授权，并限定到确切的对象和操作。持有对象标识符本身不应授予跨租户访问权限。\u003C\u002Fp>\n\u003Ch2 id=\"section-59\">后台任务和队列可能破坏隔离\u003C\u002Fh2>\n\u003Cp>异步任务通常会脱离原始 HTTP 请求上下文，这使得租户传播很容易被错误处理。包含 tenantId 的队列消息不足以证明生产者已获得授权。\u003C\u002Fp>\n\u003Cp>工作进程应携带经过验证的服务\u002F用户身份或可信的任务信封，重新建立租户上下文，并在消费者边界对重要操作重新授权。\u003C\u002Fp>\n\u003Cp>租户隔离也包括可用性。一个租户不应能够以实质性降低其他租户服务质量的方式垄断共享工作进程、队列、连接池或计算资源。\u003C\u002Fp>\n\u003Ch2 id=\"section-63\">搜索和 RAG 需要租户感知的检索\u003C\u002Fh2>\n\u003Cp>多租户 AI 引入了隔离问题的另一个副本。文档在摄取后可能被分块、嵌入并存储在向量索引中。\u003C\u002Fp>\n\u003Cp>OWASP 当前的 RAG 安全指南指出，访问控制必须在检索时强制执行，并且租户 A 的块不得被租户 B 的查询检索到。不能简单地假设文档级权限会自动在分块后继续存在。\u003C\u002Fp>\n\u003Cp>因此，向量索引需要租户\u002F访问元数据，或根据隔离设计采用物理\u002F逻辑上独立的集合。应在未经授权的内容进入模型上下文之前应用检索过滤器。\u003C\u002Fp>\n\u003Caside class=\"editorjs-callout editorjs-callout--warning my-6 rounded-xl border p-5 border-amber-300 bg-amber-50 dark:border-amber-900 dark:bg-amber-950\u002F20\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">模型绝不能成为租户过滤器\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">不要检索跨租户的块，然后指示语言模型忽略它们。一旦受保护的数据进入模型上下文，隔离边界就已经失效。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Ch2 id=\"section-68\">派生数据继承租户敏感性\u003C\u002Fh2>\n\u003Cp>嵌入、搜索索引、缩略图、生成的摘要、缓存、分析行和 AI 响应都派生自源数据。除非显式转换创建了合法的共享\u002F全局产物，否则其租户范围应遵循源数据。\u003C\u002Fp>\n\u003Cp>因此，删除和离职处理必须传播到规范行之外。删除租户文档但保留可搜索的块或缓存摘要，可能会保留跨租户或保留期后的暴露风险。\u003C\u002Fp>\n\u003Ch2 id=\"section-71\">并非所有内容都属于某个租户\u003C\u002Fh2>\n\u003Cp>多租户平台通常有意设置全局资源：产品分类、公共模板、系统权限、功能定义或公共内容。\u003C\u002Fp>\n\u003Cp>最安全的模型是显式分类：全局、租户范围、用户范围或显式跨租户。模糊的资源正是意外泄漏开始的地方。\u003C\u002Fp>\n\u003Cp>有意共享的对象应当有文档化的理由说明其为何是全局的，而不是仅仅缺少租户关联。\u003C\u002Fp>\n\u003Ch2 id=\"section-75\">平台管理员需要不同的权限模型\u003C\u002Fh2>\n\u003Cp>平台运营者可能需要为支持、合规或基础设施运维而检查多个租户。将其建模为普通的租户 ADMIN 并意外拥有全局数据库访问权限，会削弱安全性和可审计性。\u003C\u002Fp>\n\u003Cp>更好的设计使用独立的平台身份或显式的跨租户权限、更强的身份验证、目的限制、详细审计，以及在适当情况下使用审批或紧急访问控制。\u003C\u002Fp>\n\u003Cp>因此，跨租户访问应当是一项具名能力，而不是缺少租户过滤器。\u003C\u002Fp>\n\u003Ch2 id=\"section-79\">RBAC 可以与属性结合使用\u003C\u002Fh2>\n\u003Cp>有些决策取决于角色之外的因素。租户成员身份、区域、资源所有者、订阅层级、时间、项目成员身份或数据分类都可能影响访问。\u003C\u002Fp>\n\u003Cp>RBAC 和 ABAC 并不互斥。AWS 当前的多租户授权指南讨论了 RBAC、ABAC 和混合模型。角色可以定义广泛的职责，而属性则约束可以访问哪些具体资源实例。\u003C\u002Fp>\n\u003Cp>关键架构规则仍然不变：如果租户身份是一等资源边界，就不要仅将租户隔离编码为附带的角色名称。\u003C\u002Fp>\n\u003Ch2 id=\"section-83\">授权决策至少是二维的\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">主体\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">角色权限\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">租户关系\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">决策\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Alice\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">orders.read\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">订单属于 Alice 的租户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">允许\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Alice\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">orders.read\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">订单属于另一个租户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">拒绝\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Alice\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">orders.write\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">订单属于 Alice 的租户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">如果角色包含写入权限则允许\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">Alice\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">orders.write\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">订单属于另一个租户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">拒绝\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">平台支持\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">support.cross_tenant.read\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">显式支持范围 + 已审计的目标租户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">在平台策略下可能允许\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">后台工作进程\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">orders.process\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">作业租户的可信服务范围\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">仅对已验证的作业租户允许\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-85\">原始实现证据：Aaasaasa AI CMS\u003C\u002Fh2>\n\u003Caside class=\"editorjs-callout editorjs-callout--note my-6 rounded-xl border p-5 border-gray-300 bg-gray-50 dark:border-gray-700 dark:bg-gray-900\u002F40\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">原始实现证据\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">Aaasaasa AI CMS 包含一个具体的租户范围 RBAC 实现。它是关于角色授权和租户范围如何结合的有用证据，但不应将其呈现为每个存储、缓存或基础设施层都具有完整租户隔离的证明。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Cp>RBAC 服务定义了类型化权限代码，例如 cms.content.read、shop.orders.write、billing.reconcile 和 users.roles。系统角色将这些权限映射为具名职责集。\u003C\u002Fp>\n\u003Cp>角色记录使用 tenantId 创建和解析。系统角色使用租户\u002F代码复合身份进行 upsert，角色列表按租户过滤。\u003C\u002Fp>\n\u003Cp>角色更新和删除首先使用角色 ID 和租户 ID 解析角色。用户-角色分配也在当前租户上下文中存储和替换。\u003C\u002Fp>\n\u003Cp>权限解析读取按 tenantId 和 userId 双重限定的显式用户-角色分配。这防止一个租户的角色分配自动变成另一个租户的角色分配。\u003C\u002Fp>\n\u003Cp>在 API 层面，管理性 RBAC 路由在创建或修改角色之前会先解析租户上下文。这是正确的方向：权限管理本身也必须遵守租户隔离。\u003C\u002Fp>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">观察到的实现模式\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">安全含义\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">类型化权限代码\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">RBAC 操作词汇是显式的\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">系统角色 → 权限映射\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">角色聚合权限，而不是硬编码用户\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">tenantId_code 角色标识\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">同一逻辑角色可以按租户分别存在\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">角色查找使用 id + tenantId\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">角色变更受租户范围限制\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">用户-角色关系存储 tenantId\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">成员资格不能仅从角色全局推断\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">权限解析使用 tenantId + userId\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">授权在租户上下文中进行评估\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Caside class=\"editorjs-callout editorjs-callout--warning my-6 rounded-xl border p-5 border-amber-300 bg-amber-50 dark:border-amber-900 dark:bg-amber-950\u002F20\" role=\"note\">\u003Cstrong class=\"block mb-2 text-gray-900 dark:text-gray-100\">这些证据不能证明什么\u003C\u002Fstrong>\u003Cdiv class=\"text-gray-700 dark:text-gray-200\">租户范围的 RBAC 只是一层。完整的租户隔离还必须覆盖所有租户拥有的资源查找、数据库、缓存、文件、搜索\u002F向量索引、后台任务、集成和运维路径。此处的仓库证据支持 RBAC\u002F租户范围的设计模式，并不声称已通过独立审计的 SaaS 隔离。\u003C\u002Fdiv>\u003C\u002Faside>\n\u003Ch2 id=\"section-94\">为什么这一区分对 AI 代理更为重要\u003C\u002Fh2>\n\u003Cp>AI 代理可以将权限错误转化为一系列操作。如果代理被授予宽泛的 orders.read 工具而没有租户范围的强制执行，推理或提示注入失败可能导致以机器速度进行跨租户读取。\u003C\u002Fp>\n\u003Cp>代理工具描述可以提及租户约束，但强制执行仍必须在受信任的运行时\u002F服务\u002F数据层进行。自然语言指令不是授权边界。\u003C\u002Fp>\n\u003Cp>这同样适用于 RAG：代理可以拥有使用搜索工具的权限，但搜索后端仍必须防止租户 A 的查询返回租户 B 的块。\u003C\u002Fp>\n\u003Ch2 id=\"section-98\">分别测试 RBAC 和租户隔离\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">测试族\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">应证明什么\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">角色降级测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">没有权限的用户即使在自己的租户内也无法执行该操作\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">跨租户对象测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">拥有正确角色的用户仍无法访问另一租户中相同类型的资源\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">标识符篡改\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">更改对象\u002F租户 ID 不会跨越范围\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">列表\u002F批量端点测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">宽泛查询仅返回已授权的租户数据\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">缓存重用测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">使用重用进程\u002F连接的两个租户永远不会收到彼此的缓存状态\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">RLS 请求角色测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">生产请求角色无法绕过行策略\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">异步工作器测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户上下文在排队后仍然存在，并在消费时重新验证\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">向量检索测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户 A 的查询永远不会检索到租户 B 的块\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">平台管理员测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">跨租户能力是显式、狭窄且可审计的\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">离职测试\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户数据和派生索引\u002F缓存按策略移除\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>OWASP 的授权回归指南特别指出跨租户边界测试，因为缓存、查询或共享服务中的代码更改可能会在角色测试继续通过的情况下悄然破坏隔离。\u003C\u002Fp>\n\u003Ch2 id=\"section-101\">常见故障模式\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">故障模式\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">为何失败\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">检查角色但不检查租户\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">有效角色变成跨租户权限\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">信任请求中的租户 ID\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">客户端控制隔离选择器\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">限制 UI 但不限制 API\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">隐藏按钮不能保护后端资源\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户感知的详情端点，未限定范围的列表端点\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">批量读取泄露其他租户\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">大多数查询中有租户过滤器\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">一条被遗忘的路径就会破坏边界\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">全局缓存键\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">正确的数据库隔离被缓存数据绕过\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">共享向量索引且未强制执行元数据过滤器\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">RAG 检索到另一租户的块\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">将队列消息中的租户 ID 视为授权\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">伪造或错误产生的作业可以跨越租户边界\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">将平台管理员建模为普通 ADMIN\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">跨租户权力变得隐式且难以审计\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">角色在租户成员资格之间全局复制\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">用户在从未被分配的租户中获得权限\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">独立数据库但共享特权凭据\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">如果应用程序的凭据过于宽泛，它仍然可以跨数据库访问\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">RLS 与 BYPASSRLS 请求角色\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">数据库策略存在，但不保护实际请求路径\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">将随机 UUID 视为隔离\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">难以猜测的标识符减少枚举，但不授权访问\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-103\">常见误解\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">误解\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">更正\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“RBAC 提供租户隔离。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">RBAC 控制权限；隔离还需要租户\u002F资源范围限定。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“如果用户是管理员，则无需租户检查。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">管理员权限仍必须具有明确的范围。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“JWT 中的租户 ID 就足够了。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">只有在验证并一致地应用于每个受保护资源路径时，它才能作为受信任的输入。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“独立数据库消除了授权要求。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">用户仍需要在其租户内的操作级权限。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“有 tenant_id 列就意味着系统已隔离。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">该字段只有在访问路径强制执行它时才有帮助。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“UUID 防止跨租户访问。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">不可预测的标识符是纵深防御，不是授权。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“RLS 意味着应用程序代码不需要安全检查。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">应用程序授权、正确的数据库角色和策略覆盖仍然重要。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“一个共享向量数据库是不安全的。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">如果隔离可强制执行并经过验证，它可以是安全的；物理分离是一种选择，不是唯一选择。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“平台支持需要全局 ADMIN。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">跨租户支持应是一种独特、受限且可审计的权限。\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">“内部服务可以跳过租户检查。”\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">内部路径仍可能被破坏或配置错误，必须保留租户上下文。\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-105\">实用的设计顺序\u003C\u002Fh2>\n\u003Csection class=\"editorjs-process my-6\">\u003Ch3 class=\"mb-3 text-lg font-semibold\">将权限和隔离设计为独立维度\u003C\u002Fh3>\u003Cdiv class=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">1\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">1. 定义租户所有权\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">对哪些实体和资源是全局的、租户范围的、用户范围的或有意跨租户的进行分类。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">2\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">2. 定义操作\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">为读取、写入、发布、审批、管理和其他业务操作创建显式权限。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">3\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">3. 定义角色\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">根据职责对权限进行分组，而不嵌入意外的全局范围。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">4\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">4. 定义成员资格范围\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">将角色分配绑定到其适用的租户\u002F工作区\u002F项目上下文。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">5\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">5. 解析受信任的租户上下文\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">从经过身份验证、服务器验证的成员资格或服务授权中派生租户身份。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">6\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">6. 强制执行资源所有权\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">在每个租户拥有的数据\u002F服务边界应用租户范围。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">7\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">7. 添加纵深防御\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">在风险需要时使用 RLS、独立凭据、模式\u002F数据库、存储策略或策略引擎。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">8\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">8. 将范围传递到派生系统\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">在缓存、搜索、向量索引、队列、文件和分析中保留租户元数据。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">9\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">9. 显式建模跨租户操作\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">将平台管理和服务身份与普通租户角色分开。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">10\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">10. 测试两个轴\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">分别针对缺少权限和错误租户运行负面测试。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">11\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">11. 一起审计租户 + 权限\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">记录谁在哪个租户、对什么目标、以何种权限执行了操作。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"editorjs-process__step min-w-0  rounded-xl border border-gray-200 dark:border-gray-700 p-4\">\u003Cdiv class=\"text-xs font-semibold text-gray-500 dark:text-gray-400\">12\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 font-semibold text-gray-900 dark:text-gray-100\">12. 在模式\u002F运行时更改后重新测试\u003C\u002Fdiv>\u003Cdiv class=\"mt-1 text-sm text-gray-600 dark:text-gray-300\">引入新表、缓存、队列或检索路径时，隔离可能会被破坏。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fsection>\n\u003Ch2 id=\"section-107\">RBAC + 租户隔离检查清单\u003C\u002Fh2>\n\u003Cdiv class=\"overflow-x-auto\">\u003Ctable class=\"w-full border-collapse\">\u003Cthead>\u003Ctr>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">问题\u003C\u002Fth>\u003Cth class=\"border border-gray-300 px-4 py-2 text-left font-semibold\">预期答案\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">主体是谁？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">经过身份验证的用户\u002F服务\u002F代理身份\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">适用哪个租户上下文？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">服务器验证的成员资格或服务范围\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">请求哪个操作？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">类型化权限或策略操作\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">主体是否拥有该权限？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">角色\u002F策略决策\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">谁拥有目标资源？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">显式的租户\u002F全局\u002F用户分类\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">资源范围是否与权限匹配？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">租户感知的查找\u002F策略\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">存储能否绕过应用程序检查？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">纵深防御决策已记录\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">缓存是否租户安全？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">键\u002F命名空间和授权保留租户范围\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">文件\u002FBlob 是否租户安全？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">对象策略和签名 URL 签发强制执行范围\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">异步作业是否租户安全？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">已验证的上下文传播并重新验证\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">RAG\u002F搜索是否租户安全？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">在模型上下文之前强制执行元数据\u002F集合隔离\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">跨租户管理员是否显式？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">独立的权限、控制和审计\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">普通凭据能否绕过隔离？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">不能，或有严格记录的例外路径\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd class=\"border border-gray-300 px-4 py-2\">跨租户负面测试是否自动化？\u003C\u002Ftd>\u003Ctd class=\"border border-gray-300 px-4 py-2\">是，针对每个相关访问层\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch2 id=\"section-109\">边界情况与限制\u003C\u002Fh2>\n\u003Cp>一个用户可以属于多个租户。因此，当前租户应当是一个明确的执行上下文，而不是从用户账户中永久推断出来的。\u003C\u002Fp>\n\u003Cp>有些资源是有意在选定的租户之间共享的，例如协作空间或联盟数据。这需要一个明确的共享模型；假装资源属于某一个租户，然后再添加例外，通常会导致授权变得模糊不清。\u003C\u002Fp>\n\u003Cp>吵闹邻居隔离与机密性隔离相关但不同。一个租户可能永远看不到另一个租户的数据，但仍然可能耗尽共享的 CPU、队列容量或数据库连接。因此，速率限制和资源配额可以作为可用性边界，按租户进行感知。\u003C\u002Fp>\n\u003Cp>如果控制平面凭据或管理路径可以跨越边界，物理隔离并不自动安全。如果策略被集中执行、最小权限化并经过充分测试，逻辑隔离也并不自动薄弱。\u003C\u002Fp>\n\u003Cp>租户隔离要求可能因数据类别而异。公共目录数据、账单记录和私有 AI 文档可能需要在同一个 SaaS 产品内采用不同的存储和加密边界。\u003C\u002Fp>\n\u003Ch2 id=\"section-115\">什么会改变这个答案？\u003C\u002Fh2>\n\u003Cp>具体实现会随架构而变化：无服务器 API、Kubernetes、PostgreSQL、对象存储、向量数据库和策略引擎暴露出不同的隔离原语。\u003C\u002Fp>\n\u003Cp>所需的强度也会随法规、客户合同、数据敏感性、威胁模型和运营规模而变化。有些租户可能需要隔离的数据库或基础设施，而其他租户则共享池化资源。\u003C\u002Fp>\n\u003Cp>概念上的区别不会改变：执行某项操作的权限与跨越租户边界的权限不是一回事。\u003C\u002Fp>\n\u003Ch2 id=\"section-119\">相关规范知识\u003C\u002Fh2>\n\u003Cp>S01 是企业 AI 架构和 AI 治理的安全边界前提。一旦 AI 工具、RAG 或代理在多租户数据上运行，租户身份就必须贯穿检索、工具执行、记忆、缓存和审计追踪。\u003C\u002Fp>\n\u003Cp>它也与代理式 AI 直接相关：在代理能够读取或修改业务资源之前，工具能力和角色权限仍然必须受到租户所有权的约束。\u003C\u002Fp>\n\u003Caside class=\"editorjs-referral my-6\">\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fmcp-vs-a2a-vs-ucp-vs-ap2-vs-a2ui-the-agent-protocol-stack-explained\" class=\"flex flex-col sm:flex-row gap-4 rounded-xl border border-gray-200 dark:border-gray-700 p-4 transition hover:border-primary-500\">\u003Cdiv class=\"min-w-0 flex-1\">\u003Cstrong class=\"block text-lg text-gray-900 dark:text-gray-100\">MCP vs A2A vs UCP vs AP2 vs A2UI：代理协议栈详解\u003C\u002Fstrong>\u003Cp class=\"mt-2 text-sm text-gray-600 dark:text-gray-300\">协议互操作性不能取代授权或租户隔离。能力发现和业务权限仍然是独立的架构关注点。\u003C\u002Fp>\u003Cspan class=\"mt-3 inline-flex text-sm font-medium text-primary-600 dark:text-primary-400\">阅读协议栈文章 →\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fa>\u003C\u002Faside>\n\u003Cp>对于 RAG，必须在受保护的分块进入模型上下文之前强制执行租户隔离。\u003C\u002Fp>\n\u003Caside class=\"editorjs-referral my-6\">\u003Ca href=\"https:\u002F\u002Fstajic.de\u002Fzh\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\" class=\"flex flex-col sm:flex-row gap-4 rounded-xl border border-gray-200 dark:border-gray-700 p-4 transition hover:border-primary-500\">\u003Cdiv class=\"min-w-0 flex-1\">\u003Cstrong class=\"block text-lg text-gray-900 dark:text-gray-100\">什么是 RAG？对其工作原理的最简单解释\u003C\u002Fstrong>\u003Cp class=\"mt-2 text-sm text-gray-600 dark:text-gray-300\">理解必须在何处强制执行租户感知的源过滤和向量存储隔离的检索基础。\u003C\u002Fp>\u003Cspan class=\"mt-3 inline-flex text-sm font-medium text-primary-600 dark:text-primary-400\">阅读 RAG 基础 →\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fa>\u003C\u002Faside>\n\u003Ch2 id=\"section-125\">常见问题\u003C\u002Fh2>\n\u003Csection class=\"editorjs-faq my-6 rounded-xl border border-gray-200 p-5 dark:border-gray-700\">\u003Ch3 class=\"mb-3 text-lg font-semibold\">RBAC 与租户隔离常见问题\u003C\u002Fh3>\u003Cdiv id=\"faq1\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">RBAC 和租户隔离有什么区别？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">RBAC 决定主体可以执行哪些操作。租户隔离决定这些操作可以访问哪个租户的资源。安全的多租户应用程序通常需要两者兼备。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq2\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">ADMIN 角色是否自动允许访问所有租户？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">不。ADMIN 应当具有明确的范围。租户管理员通常只在该租户内拥有广泛权限，而跨租户的平台管理应当单独建模。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq3\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">仅靠身份验证就足以实现租户隔离吗？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">不。身份验证证明身份。授权控制允许的操作。租户隔离还额外防止这些操作触及错误租户的资源。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq4\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">tenantId 应该存储在 JWT 中吗？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">它可以作为租户上下文的输入之一，但服务器必须验证当前成员资格\u002F权限，并在受保护资源边界处强制执行范围。仅凭声明不能取代隔离控制。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq5\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">我需要为每个租户使用单独的数据库吗？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">不一定。共享表、RLS、模式、数据库、基础设施和混合隔离模型都可能有效，具体取决于风险和运营要求。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq6\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">PostgreSQL RLS 可以取代应用程序代码中的租户过滤器吗？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">RLS 可以提供强大的纵深防御，但正确的数据库角色、请求上下文、策略覆盖范围和应用程序级授权仍然很重要。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq7\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">RAG 应如何强制执行租户隔离？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">应在检索期间强制执行租户\u002F访问范围，以便未经授权的分块永远不会进入模型上下文。在分块和索引过程中保留访问元数据。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq8\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">一个用户可以在不同租户中拥有不同角色吗？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">可以。这在 B2B SaaS 中很常见，也是将角色分配按租户成员资格进行范围限定的有力理由，而不是将角色视为全局附加到用户。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv id=\"faq9\" class=\"border-t border-gray-200 py-4 first:border-t-0 dark:border-gray-700\">\u003Ch4 class=\"font-semibold text-gray-900 dark:text-gray-100\">测试租户隔离的最佳方法是什么？\u003C\u002Fh4>\u003Cdiv class=\"mt-2 text-gray-600 dark:text-gray-300\">使用负向跨租户测试：创建至少两个租户，在一个租户中为用户授予有效权限，然后证明每个受保护路径都拒绝对另一个租户资源的访问。\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fsection>\n\u003Ch2 id=\"section-127\">术语表\u003C\u002Fh2>\n\u003Csection class=\"editorjs-glossary my-6 rounded-xl border border-gray-200 dark:border-gray-700 p-5\">\u003Ch3 class=\"mb-3 text-lg font-semibold\">关键多租户安全术语\u003C\u002Fh3>\u003Cdl>\u003Cdiv id=\"rbac\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">RBAC\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">基于角色的访问控制：一种授权模型，将权限与角色关联，并将用户或主体分配到这些角色。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"tenant\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">租户\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">共享多租户系统中的客户、组织、工作区或其他隔离的逻辑消费者。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"tenant-isolation\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">租户隔离\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">防止一个租户在共享系统中访问、修改或接收另一个租户资源的机制。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"authentication\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">身份验证\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">验证用户、服务或其他主体身份的过程。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"authorization\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">授权\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">确定主体是否可以对资源执行所请求操作的决策过程。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"permission\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">权限\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">已定义的允许操作或能力，例如 orders.read 或 users.write。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"role\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">角色\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">与职责或职能相关联的权限的命名分组。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"abac\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">ABAC\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">基于属性的访问控制：基于主体、资源、操作或环境属性的授权。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"row-level-security\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">行级安全\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">数据库策略机制，限制数据库角色或会话可以读取或修改哪些行。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"cross-tenant-access\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">跨租户访问\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">在一个租户上下文中运行的主体访问属于另一个租户资源的任何访问路径。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"platform-administrator\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">平台管理员\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">具有明确建模权限的特权操作身份，可能跨越多个租户。\u003C\u002Fdd>\u003C\u002Fdiv>\u003Cdiv id=\"tenant-context\" class=\"border-t border-gray-200 dark:border-gray-700 py-3 first:border-t-0\">\u003Cdt class=\"font-semibold text-gray-900 dark:text-gray-100\">租户上下文\u003C\u002Fdt>\u003Cdd class=\"mt-1 text-gray-600 dark:text-gray-300\">当前请求、作业或代理操作执行时所处的已验证租户范围。\u003C\u002Fdd>\u003C\u002Fdiv>\u003C\u002Fdl>\u003C\u002Fsection>\n\u003Ch2 id=\"section-129\">结论\u003C\u002Fh2>\n\u003Cp>RBAC 和租户隔离是互补的安全机制，而非相互竞争。RBAC 构建操作权限；租户隔离约束该权限可以适用的资源边界。\u003C\u002Fp>\n\u003Cp>因此，一个健壮的多租户请求需要的不仅仅是“用户拥有 ADMIN 角色”。它需要已验证的主体、已验证的租户上下文、允许的操作、租户范围内的目标，以及在每个可能承载租户数据的资源层上执行强制措施。\u003C\u002Fp>\n\u003Cp>最简短可靠的规则是：授权操作，然后隔离范围——并且永远不要假设其中一个能证明另一个。\u003C\u002Fp>\n\u003Ch2 id=\"section-133\">主要来源和当前指南\u003C\u002Fh2>\n\u003Cp>以下来源支持 RBAC 定义和当前租户隔离指南。Aaasaasa AI CMS 部分是原始实现证据，并有意限定在已验证的代码模式范围内。\u003C\u002Fp>\n\u003Ca href=\"https:\u002F\u002Fcsrc.nist.gov\u002Fprojects\u002Frole-based-access-control\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">NIST — 基于角色的访问控制\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">NIST 对 RBAC 模型和 INCITS RBAC 标准的概述，包括用户、角色、权限、操作和对象。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fcsrc.nist.gov\u002Fglossary\u002Fterm\u002Frole_based_access_control\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">NIST CSRC — RBAC 术语表\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">NIST 当前术语表对基于角色的访问控制的定义，即通过角色进行权限分配。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fwhitepapers\u002Flatest\u002Fsaas-tenant-isolation-strategies\u002Fthe-isolation-mindset.html\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">AWS — 隔离思维模式\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">AWS SaaS 指南明确区分身份验证\u002F授权与租户隔离，并推荐共享隔离机制。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fprescriptive-guidance\u002Flatest\u002Fsaas-multitenant-api-access-authorization\u002Ffaq.html\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">AWS — 多租户授权常见问题\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">当前指南解释 SaaS 应用程序中授权与租户隔离之间的区别。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fprescriptive-guidance\u002Flatest\u002Fsaas-multitenant-api-access-authorization\u002Favp-design-considerations.html\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">AWS — 多租户设计考虑因素\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">当前 SaaS 指南区分租户隔离与授权，并讨论池化\u002F隔离授权策略模型。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FMulti_Tenant_Security_Cheat_Sheet.html\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">OWASP — 多租户应用程序安全备忘单\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">当前关于租户上下文、数据库隔离、缓存、存储、队列、测试和跨租户访问预防的实用指南。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FRAG_Security_Cheat_Sheet.html\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">OWASP — RAG 安全备忘单\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">当前指南要求在检索时进行访问控制，并为多租户向量存储提供租户隔离。\u003C\u002Fp>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FAuthorization_Regression_Testing_Cheat_Sheet.html\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"editorjs-link-tool block border border-gray-200 dark:border-gray-700 rounded-lg p-4 transition text-gray-900 dark:text-gray-100 hover:border-primary-500 hover:bg-primary-50 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100\">\u003Cstrong class=\"block font-semibold\">OWASP — 授权回归测试\u003C\u002Fstrong>\u003Cp class=\"text-sm text-gray-600 dark:text-gray-400\">当前测试指南，包括角色降级和跨租户边界测试。\u003C\u002Fp>\u003C\u002Fa>",{"time":212,"blocks":213,"version":1410},1791485517401,[214,220,228,235,242,250,255,260,265,270,275,280,285,290,295,300,305,310,336,341,346,351,356,361,401,406,426,431,436,441,446,451,456,461,466,471,476,481,498,503,508,513,518,525,530,563,568,573,578,583,588,593,598,603,608,613,618,623,628,633,638,643,648,653,658,663,668,674,679,684,689,694,699,704,709,714,719,724,729,734,739,744,749,754,786,791,797,802,807,812,817,822,848,854,859,864,869,874,879,917,922,927,974,979,1017,1022,1064,1069,1118,1123,1128,1133,1138,1143,1148,1153,1158,1163,1168,1173,1178,1183,1192,1197,1205,1210,1252,1257,1307,1312,1317,1322,1327,1332,1337,1347,1356,1365,1374,1383,1392,1401],{"id":215,"data":216,"type":218,"tunes":219},"intro",{"text":217},"RBAC 和租户隔离解决了多租户系统中两个不同的安全问题。基于角色的访问控制（RBAC）决定已认证主体被允许做什么，例如读取订单、编辑产品或管理用户。租户隔离决定该主体被允许访问哪个租户的数据、资源和执行上下文。一个用户可能被正确认证并正确分配了 RBAC 角色，但如果应用程序允许该角色操作另一个租户的资源，仍然会遭遇安全失败。","paragraph",{},{"id":221,"data":222,"type":226,"tunes":227},"direct",{"body":223,"title":224,"variant":225},"\u003Cstrong>RBAC 回答“这个身份可以做什么？”租户隔离回答“它可以在谁的边界内做这件事？”\u003C\u002Fstrong>\u003Cbr>\u003Cbr>安全的多租户应用程序通常需要两者兼备。租户管理员可能拥有广泛的权限，但这些权限应保持在管理员所属租户的范围内，除非存在明确独立的平台级权限。","直接回答","info","callout",{},{"id":229,"data":230,"type":226,"tunes":234},"boundary",{"body":231,"title":232,"variant":233},"给用户分配 \u003Ccode>ADMIN\u003C\u002Fcode> 角色并不自动意味着“仅限租户 A 的管理员”。该角色必须与已验证的租户上下文以及目标资源的租户所有权一起评估。否则，一个有效的角色可能变成跨租户权限。","角色不是租户边界","warning",{},{"id":236,"data":237,"type":226,"tunes":241},"current",{"body":238,"title":239,"variant":240},"底层区别是稳定的。NIST 围绕用户、角色、权限、操作和对象来定义 RBAC。当前 AWS SaaS 指南明确指出，身份验证和授权并不等同于租户隔离，并且如果未单独强制执行隔离，用户即使已通过身份验证和授权，仍可能访问另一个租户的资源。OWASP 当前的多租户安全指南同样将租户隔离视为一项跨层要求，涵盖 API、数据库、缓存、存储、队列和其他共享资源。","当前来源说明 — 2026 年 10 月 8 日","note",{},{"id":243,"data":244,"type":248,"tunes":249},"toc",{"title":245,"maxLevel":246,"minLevel":247},"目录",3,2,"tableOfContents",{},{"id":251,"data":252,"type":42,"tunes":254},"h-meaning",{"text":253,"level":247},"RBAC 真正控制什么",{},{"id":256,"data":257,"type":218,"tunes":259},"p-rbac-1",{"text":258},"RBAC 是一种授权模型，其中权限与角色关联，用户被分配到这些角色。角色充当身份与权限之间的管理抽象。",{},{"id":261,"data":262,"type":218,"tunes":264},"p-rbac-2",{"text":263},"NIST 经典的 RBAC 工作围绕用户、角色、权限、操作和对象将其形式化。实际好处是，组织可以通过相对稳定的工作或职责角色来管理授权，而不是将每个权限直接附加到每个用户。",{},{"id":266,"data":267,"type":218,"tunes":269},"p-rbac-3",{"text":268},"例如，EDITOR 这样的角色可以表示：可以读取内容、写入内容和发布内容。ACCOUNTANT 这样的角色可以表示：可以读取账单数据、核对发票和批准结算。",{},{"id":271,"data":272,"type":42,"tunes":274},"h-tenant",{"text":273,"level":247},"租户隔离真正控制什么",{},{"id":276,"data":277,"type":218,"tunes":279},"p-tenant-1",{"text":278},"租户隔离是一组机制，用于防止一个租户在共享系统中读取、修改、影响或意外接收另一个租户的资源。",{},{"id":281,"data":282,"type":218,"tunes":284},"p-tenant-2",{"text":283},"受保护的边界比数据库行更广泛。租户特定状态可能存在于关系表、对象存储、向量索引、缓存、搜索索引、队列消息、文件、临时产物、后台作业、分析、速率限制和基础设施资源中。",{},{"id":286,"data":287,"type":218,"tunes":289},"p-tenant-3",{"text":288},"AWS 的 SaaS 指南明确指出了这一区别：授权授予对资源的访问权限，而租户隔离确保即使基础设施是共享的，这些资源也不会跨越错误的租户边界。",{},{"id":291,"data":292,"type":42,"tunes":294},"h-simple",{"text":293,"level":247},"最简单的例子",{},{"id":296,"data":297,"type":218,"tunes":299},"p-simple-1",{"text":298},"假设 Alice 是租户 A 的管理员，Bob 是租户 B 的管理员。两个用户都合法地拥有相同的 ADMIN 角色。",{},{"id":301,"data":302,"type":218,"tunes":304},"p-simple-2",{"text":303},"RBAC 可以正确判断两个用户都可以执行诸如 users.read 之类的操作。但当 Alice 请求用户 ID 847 时，应用程序仍必须验证用户 847 属于租户 A。",{},{"id":306,"data":307,"type":218,"tunes":309},"p-simple-3",{"text":308},"如果 API 只检查“Alice 拥有 ADMIN”，然后执行 SELECT * FROM users WHERE id = 847，那么 RBAC 成功了，而租户隔离失败了。",{},{"id":311,"data":312,"type":334,"tunes":335},"simple-flow",{"steps":313,"title":332,"orientation":333},[314,317,320,323,326,329],{"label":315,"description":316},"1. 认证主体","确定用户、服务或代理是谁。",{"label":318,"description":319},"2. 解析已验证的租户上下文","从可信的服务器端身份\u002F成员信息中确定适用哪个租户上下文。",{"label":321,"description":322},"3. 解析权限","评估主体的角色或策略是否允许所请求的操作。",{"label":324,"description":325},"4. 限定目标资源范围","验证目标对象属于允许的租户或明确共享的范围。",{"label":327,"description":328},"5. 在访问边界强制执行","在应用租户约束的情况下执行数据库、缓存、存储、队列或服务操作。",{"label":330,"description":331},"6. 审计两个维度","记录主体、租户、操作、目标和结果，以便跨租户尝试可见。","正确的多租户授权决策","auto","processFlow",{},{"id":337,"data":338,"type":42,"tunes":340},"h-stops",{"text":339,"level":247},"简单示例的局限",{},{"id":342,"data":343,"type":218,"tunes":345},"p-stops-1",{"text":344},"真实系统通常包含多种身份类别：租户用户、平台管理员、后台工作进程、集成、代理以及跨租户运营服务。其中一些身份合法地跨越租户边界。",{},{"id":347,"data":348,"type":218,"tunes":350},"p-stops-2",{"text":349},"这并不消除隔离的必要性。它意味着跨租户权限必须是显式的、狭窄的且可单独审计的，而不是从全局角色或无范围限制的数据库连接中意外产生的。",{},{"id":352,"data":353,"type":218,"tunes":355},"p-stops-3",{"text":354},"租户隔离也可能因层而异。一个产品可能共享应用服务器但分离数据库，或者使用带有行级策略的共享数据库，同时为高级租户提供隔离的存储或计算资源。不存在单一的通用隔离拓扑。",{},{"id":357,"data":358,"type":42,"tunes":360},"h-compare",{"text":359,"level":247},"RBAC 与租户隔离",{},{"id":362,"data":363,"type":399,"tunes":400},"core-comparison",{"rows":364,"title":390,"layout":391,"columns":392},[365,370,374,378,382,386],{"id":366,"label":367,"values":368},"question","主要问题",[369,369],"",{"id":371,"label":372,"values":373},"unit","典型单元",[369,369],{"id":375,"label":376,"values":377},"example","示例",[369,369],{"id":379,"label":380,"values":381},"failure","典型故障",[369,369],{"id":383,"label":384,"values":385},"implementation","典型实现",[369,369],{"id":387,"label":388,"values":389},"scope","能否单独存在？",[369,369],"两个不同的安全维度","table",[393,396],{"id":394,"label":395},"rbac","RBAC",{"id":397,"label":398},"tenant","租户隔离","comparison",{},{"id":402,"data":403,"type":42,"tunes":405},"h-authn",{"text":404,"level":247},"认证、授权和隔离是三种不同的检查",{},{"id":407,"data":408,"type":391,"tunes":425},"three-checks",{"content":409,"stretched":43,"withHeadings":14},[410,414,418,422],[411,412,413],"层","问题","示例故障",[415,416,417],"认证","这个主体是谁？","攻击者冒充 Alice",[419,420,421],"授权 \u002F RBAC","这个主体可以执行此操作吗？","查看者可以删除用户",[398,423,424],"此操作可以触及此租户\u002F资源边界吗？","租户 A 管理员读取租户 B 的订单",{},{"id":427,"data":428,"type":218,"tunes":430},"p-authn-1",{"text":429},"这些检查相互关联但不可替代。认证可以完美无缺，而授权却失败。授权可以正确无误，而租户隔离却失败。安全的 SaaS 请求路径需要所有适用的边界。",{},{"id":432,"data":433,"type":42,"tunes":435},"h-role-scope",{"text":434,"level":247},"角色需要作用域",{},{"id":437,"data":438,"type":218,"tunes":440},"p-role-scope-1",{"text":439},"没有作用域，ADMIN 这个词是不完整的。它可以指平台管理员、租户管理员、项目管理员、工作区管理员或某个子系统的管理员。",{},{"id":442,"data":443,"type":218,"tunes":445},"p-role-scope-2",{"text":444},"在多租户系统中，角色分配通常应与租户成员资格或其他显式资源作用域相关联。同一用户可以在租户 A 中合法地是 ADMIN，而在租户 B 中是 VIEWER。",{},{"id":447,"data":448,"type":218,"tunes":450},"p-role-scope-3",{"text":449},"忽略这种区别的全局角色模型，即使权限映射本身是正确的，也可能造成权限泄漏。",{},{"id":452,"data":453,"type":42,"tunes":455},"h-context",{"text":454,"level":247},"租户上下文必须来自可信路径",{},{"id":457,"data":458,"type":218,"tunes":460},"p-context-1",{"text":459},"客户端提供的租户 ID 作为选择器是有用的，但它不是权限的证明。服务器必须根据已认证的身份和当前授权数据来推导或验证租户成员资格。",{},{"id":462,"data":463,"type":218,"tunes":465},"p-context-2",{"text":464},"OWASP 当前的多租户指南建议在请求生命周期的早期建立租户上下文，并明确警告不要将客户端标头或请求参数视为授权证明。",{},{"id":467,"data":468,"type":218,"tunes":470},"p-context-3",{"text":469},"这一点很重要，因为从 tenant=A 到 tenant=B 的简单请求修改不应足以跨越隔离边界。",{},{"id":472,"data":473,"type":42,"tunes":475},"h-query",{"text":474,"level":247},"租户作用域应属于资源查找的一部分",{},{"id":477,"data":478,"type":218,"tunes":480},"p-query-1",{"text":479},"一种常见的应用层隔离模式是在解析资源的同一个查询中包含租户范围。",{},{"id":482,"data":483,"type":391,"tunes":497},"query-table",{"content":484,"stretched":43,"withHeadings":14},[485,488,491,494],[486,487],"弱查找","更强的租户范围查找",[489,490],"findFirst({ where: { id } })","findFirst({ where: { id, tenantId } })",[492,493],"UPDATE orders SET ... WHERE id = ?","UPDATE orders SET ... WHERE id = ? AND tenant_id = ?",[495,496],"cache.get('user:' + id)","cache.get('tenant:' + tenantId + ':user:' + id)",{},{"id":499,"data":500,"type":218,"tunes":502},"p-query-2",{"text":501},"这种模式不是唯一可能的隔离机制，但它使租户所有权贴近数据访问操作，并防止对象 ID 成为跨租户能力。",{},{"id":504,"data":505,"type":42,"tunes":507},"h-defense",{"text":506,"level":247},"应用检查有用，但隔离不应依赖于完美的开发者行为",{},{"id":509,"data":510,"type":218,"tunes":512},"p-defense-1",{"text":511},"AWS 的隔离指南明确警告不要将隔离执行仅留给服务开发者。在大型代码库中，最终可能有一个查询、缓存键或工作路径会遗漏租户范围。",{},{"id":514,"data":515,"type":218,"tunes":517},"p-defense-2",{"text":516},"因此，纵深防御可以将隔离移至共享中间件、仓库\u002F服务层、策略引擎、数据库行级安全、专用凭据、独立模式或独立数据库，具体取决于风险和架构。",{},{"id":519,"data":520,"type":226,"tunes":524},"defense-rule",{"body":521,"title":522,"variant":523},"最强的边界是普通应用代码无法通过省略一个 \u003Ccode>tenantId\u003C\u002Fcode> 条件而随意绕过。","隔离应该难以被遗忘","success",{},{"id":526,"data":527,"type":42,"tunes":529},"h-db",{"text":528,"level":247},"数据库隔离策略",{},{"id":531,"data":532,"type":391,"tunes":562},"db-table",{"content":533,"stretched":43,"withHeadings":14},[534,538,542,546,550,554,558],[535,536,537],"策略","边界","强度 \u002F 权衡",[539,540,541],"共享表 + 租户键","行\u002F应用策略","操作高效；需要详尽的租户范围和强测试",[543,544,545],"共享表 + 数据库 RLS","数据库策略边界","减少对每个应用查询的依赖；需要正确的角色、会话\u002F事务租户上下文和策略覆盖",[547,548,549],"独立模式","命名空间 \u002F 数据库角色边界","更强的逻辑分离；更多的操作复杂性",[551,552,553],"独立数据库","数据库 \u002F 凭据边界","强隔离和更简单的爆炸半径故事；更高的配置和操作成本",[555,556,557],"独立基础设施\u002F账户","基础设施边界","最强的粗粒度分离；最高的成本和操作开销",[559,560,561],"混合","按工作负载\u002F数据类别","仅在风险\u002F合规性证明合理时允许更强的隔离",{},{"id":564,"data":565,"type":218,"tunes":567},"p-db-1",{"text":566},"OWASP 当前的多租户安全备忘单列出了独立数据库、独立模式、带行级控制的共享表和混合模型。正确的模型取决于威胁级别、合规性、性能和操作成本。",{},{"id":569,"data":570,"type":42,"tunes":572},"h-rls",{"text":571,"level":247},"PostgreSQL 行级安全可以提供纵深防御",{},{"id":574,"data":575,"type":218,"tunes":577},"p-rls-1",{"text":576},"对于共享表，PostgreSQL 行级安全可以在数据库层强制执行租户谓词，以便普通查询无法看到活动租户策略之外的行。",{},{"id":579,"data":580,"type":218,"tunes":582},"p-rls-2",{"text":581},"然而，RLS 不是魔法。PostgreSQL 超级用户和具有 BYPASSRLS 的角色可以绕过行策略。因此，OWASP 建议使用最小权限的请求路径角色，并测试生产环境中使用的相同连接\u002F池化模式。",{},{"id":584,"data":585,"type":218,"tunes":587},"p-rls-3",{"text":586},"连接重用是另一个重要的边缘情况：必须为每个事务\u002F请求安全地设置和重置租户上下文，以便一个池化连接不会泄漏先前的租户状态。",{},{"id":589,"data":590,"type":42,"tunes":592},"h-cache",{"text":591,"level":247},"租户隔离必须包括缓存",{},{"id":594,"data":595,"type":218,"tunes":597},"p-cache-1",{"text":596},"数据库查询可以完美地限定范围，但仍然通过共享缓存键泄漏数据。",{},{"id":599,"data":600,"type":218,"tunes":602},"p-cache-2",{"text":601},"如果 user:42 同时存在于租户 A 和租户 B 中，全局缓存键可能会返回错误租户的值。租户敏感的缓存键应包含每个改变可见性或结果语义的属性，通常是租户、用户、区域设置、功能集或权限版本。",{},{"id":604,"data":605,"type":218,"tunes":607},"p-cache-3",{"text":606},"缓存分区是纵深防御，而不是授权的替代品。在返回受保护的缓存内容之前，请求仍然需要被授权。",{},{"id":609,"data":610,"type":42,"tunes":612},"h-storage",{"text":611,"level":247},"文件和对象存储需要自己的租户边界",{},{"id":614,"data":615,"type":218,"tunes":617},"p-storage-1",{"text":616},"对象存储应区分全局对象、租户范围对象和用户范围对象。除非访问策略实际约束了读写，否则仅靠文件夹前缀只是一种命名约定。",{},{"id":619,"data":620,"type":218,"tunes":622},"p-storage-2",{"text":621},"当风险或合规要求更强的隔离时，更稳健的设计可以使用租户感知的对象键、存储桶策略、独立的存储桶\u002F账户或租户特定的加密密钥。",{},{"id":624,"data":625,"type":218,"tunes":627},"p-storage-3",{"text":626},"签名 URL 必须在签发前获得授权，并限定到确切的对象和操作。持有对象标识符本身不应授予跨租户访问权限。",{},{"id":629,"data":630,"type":42,"tunes":632},"h-queues",{"text":631,"level":247},"后台任务和队列可能破坏隔离",{},{"id":634,"data":635,"type":218,"tunes":637},"p-queue-1",{"text":636},"异步任务通常会脱离原始 HTTP 请求上下文，这使得租户传播很容易被错误处理。包含 tenantId 的队列消息不足以证明生产者已获得授权。",{},{"id":639,"data":640,"type":218,"tunes":642},"p-queue-2",{"text":641},"工作进程应携带经过验证的服务\u002F用户身份或可信的任务信封，重新建立租户上下文，并在消费者边界对重要操作重新授权。",{},{"id":644,"data":645,"type":218,"tunes":647},"p-queue-3",{"text":646},"租户隔离也包括可用性。一个租户不应能够以实质性降低其他租户服务质量的方式垄断共享工作进程、队列、连接池或计算资源。",{},{"id":649,"data":650,"type":42,"tunes":652},"h-search",{"text":651,"level":247},"搜索和 RAG 需要租户感知的检索",{},{"id":654,"data":655,"type":218,"tunes":657},"p-search-1",{"text":656},"多租户 AI 引入了隔离问题的另一个副本。文档在摄取后可能被分块、嵌入并存储在向量索引中。",{},{"id":659,"data":660,"type":218,"tunes":662},"p-search-2",{"text":661},"OWASP 当前的 RAG 安全指南指出，访问控制必须在检索时强制执行，并且租户 A 的块不得被租户 B 的查询检索到。不能简单地假设文档级权限会自动在分块后继续存在。",{},{"id":664,"data":665,"type":218,"tunes":667},"p-search-3",{"text":666},"因此，向量索引需要租户\u002F访问元数据，或根据隔离设计采用物理\u002F逻辑上独立的集合。应在未经授权的内容进入模型上下文之前应用检索过滤器。",{},{"id":669,"data":670,"type":226,"tunes":673},"rag-rule",{"body":671,"title":672,"variant":233},"不要检索跨租户的块，然后指示语言模型忽略它们。一旦受保护的数据进入模型上下文，隔离边界就已经失效。","模型绝不能成为租户过滤器",{},{"id":675,"data":676,"type":42,"tunes":678},"h-derived",{"text":677,"level":247},"派生数据继承租户敏感性",{},{"id":680,"data":681,"type":218,"tunes":683},"p-derived-1",{"text":682},"嵌入、搜索索引、缩略图、生成的摘要、缓存、分析行和 AI 响应都派生自源数据。除非显式转换创建了合法的共享\u002F全局产物，否则其租户范围应遵循源数据。",{},{"id":685,"data":686,"type":218,"tunes":688},"p-derived-2",{"text":687},"因此，删除和离职处理必须传播到规范行之外。删除租户文档但保留可搜索的块或缓存摘要，可能会保留跨租户或保留期后的暴露风险。",{},{"id":690,"data":691,"type":42,"tunes":693},"h-shared",{"text":692,"level":247},"并非所有内容都属于某个租户",{},{"id":695,"data":696,"type":218,"tunes":698},"p-shared-1",{"text":697},"多租户平台通常有意设置全局资源：产品分类、公共模板、系统权限、功能定义或公共内容。",{},{"id":700,"data":701,"type":218,"tunes":703},"p-shared-2",{"text":702},"最安全的模型是显式分类：全局、租户范围、用户范围或显式跨租户。模糊的资源正是意外泄漏开始的地方。",{},{"id":705,"data":706,"type":218,"tunes":708},"p-shared-3",{"text":707},"有意共享的对象应当有文档化的理由说明其为何是全局的，而不是仅仅缺少租户关联。",{},{"id":710,"data":711,"type":42,"tunes":713},"h-platform-admin",{"text":712,"level":247},"平台管理员需要不同的权限模型",{},{"id":715,"data":716,"type":218,"tunes":718},"p-platform-1",{"text":717},"平台运营者可能需要为支持、合规或基础设施运维而检查多个租户。将其建模为普通的租户 ADMIN 并意外拥有全局数据库访问权限，会削弱安全性和可审计性。",{},{"id":720,"data":721,"type":218,"tunes":723},"p-platform-2",{"text":722},"更好的设计使用独立的平台身份或显式的跨租户权限、更强的身份验证、目的限制、详细审计，以及在适当情况下使用审批或紧急访问控制。",{},{"id":725,"data":726,"type":218,"tunes":728},"p-platform-3",{"text":727},"因此，跨租户访问应当是一项具名能力，而不是缺少租户过滤器。",{},{"id":730,"data":731,"type":42,"tunes":733},"h-abac",{"text":732,"level":247},"RBAC 可以与属性结合使用",{},{"id":735,"data":736,"type":218,"tunes":738},"p-abac-1",{"text":737},"有些决策取决于角色之外的因素。租户成员身份、区域、资源所有者、订阅层级、时间、项目成员身份或数据分类都可能影响访问。",{},{"id":740,"data":741,"type":218,"tunes":743},"p-abac-2",{"text":742},"RBAC 和 ABAC 并不互斥。AWS 当前的多租户授权指南讨论了 RBAC、ABAC 和混合模型。角色可以定义广泛的职责，而属性则约束可以访问哪些具体资源实例。",{},{"id":745,"data":746,"type":218,"tunes":748},"p-abac-3",{"text":747},"关键架构规则仍然不变：如果租户身份是一等资源边界，就不要仅将租户隔离编码为附带的角色名称。",{},{"id":750,"data":751,"type":42,"tunes":753},"h-matrix",{"text":752,"level":247},"授权决策至少是二维的",{},{"id":755,"data":756,"type":391,"tunes":785},"matrix-table",{"content":757,"stretched":43,"withHeadings":14},[758,763,768,771,774,775,780],[759,760,761,762],"主体","角色权限","租户关系","决策",[764,765,766,767],"Alice","orders.read","订单属于 Alice 的租户","允许",[764,765,769,770],"订单属于另一个租户","拒绝",[764,772,766,773],"orders.write","如果角色包含写入权限则允许",[764,772,769,770],[776,777,778,779],"平台支持","support.cross_tenant.read","显式支持范围 + 已审计的目标租户","在平台策略下可能允许",[781,782,783,784],"后台工作进程","orders.process","作业租户的可信服务范围","仅对已验证的作业租户允许",{},{"id":787,"data":788,"type":42,"tunes":790},"h-implementation",{"text":789,"level":247},"原始实现证据：Aaasaasa AI CMS",{},{"id":792,"data":793,"type":226,"tunes":796},"impl-note",{"body":794,"title":795,"variant":240},"Aaasaasa AI CMS 包含一个具体的租户范围 RBAC 实现。它是关于角色授权和租户范围如何结合的有用证据，但不应将其呈现为每个存储、缓存或基础设施层都具有完整租户隔离的证明。","原始实现证据",{},{"id":798,"data":799,"type":218,"tunes":801},"p-impl-1",{"text":800},"RBAC 服务定义了类型化权限代码，例如 cms.content.read、shop.orders.write、billing.reconcile 和 users.roles。系统角色将这些权限映射为具名职责集。",{},{"id":803,"data":804,"type":218,"tunes":806},"p-impl-2",{"text":805},"角色记录使用 tenantId 创建和解析。系统角色使用租户\u002F代码复合身份进行 upsert，角色列表按租户过滤。",{},{"id":808,"data":809,"type":218,"tunes":811},"p-impl-3",{"text":810},"角色更新和删除首先使用角色 ID 和租户 ID 解析角色。用户-角色分配也在当前租户上下文中存储和替换。",{},{"id":813,"data":814,"type":218,"tunes":816},"p-impl-4",{"text":815},"权限解析读取按 tenantId 和 userId 双重限定的显式用户-角色分配。这防止一个租户的角色分配自动变成另一个租户的角色分配。",{},{"id":818,"data":819,"type":218,"tunes":821},"p-impl-5",{"text":820},"在 API 层面，管理性 RBAC 路由在创建或修改角色之前会先解析租户上下文。这是正确的方向：权限管理本身也必须遵守租户隔离。",{},{"id":823,"data":824,"type":391,"tunes":847},"impl-table",{"content":825,"stretched":43,"withHeadings":14},[826,829,832,835,838,841,844],[827,828],"观察到的实现模式","安全含义",[830,831],"类型化权限代码","RBAC 操作词汇是显式的",[833,834],"系统角色 → 权限映射","角色聚合权限，而不是硬编码用户",[836,837],"tenantId_code 角色标识","同一逻辑角色可以按租户分别存在",[839,840],"角色查找使用 id + tenantId","角色变更受租户范围限制",[842,843],"用户-角色关系存储 tenantId","成员资格不能仅从角色全局推断",[845,846],"权限解析使用 tenantId + userId","授权在租户上下文中进行评估",{},{"id":849,"data":850,"type":226,"tunes":853},"impl-boundary",{"body":851,"title":852,"variant":233},"租户范围的 RBAC 只是一层。完整的租户隔离还必须覆盖所有租户拥有的资源查找、数据库、缓存、文件、搜索\u002F向量索引、后台任务、集成和运维路径。此处的仓库证据支持 RBAC\u002F租户范围的设计模式，并不声称已通过独立审计的 SaaS 隔离。","这些证据不能证明什么",{},{"id":855,"data":856,"type":42,"tunes":858},"h-ai",{"text":857,"level":247},"为什么这一区分对 AI 代理更为重要",{},{"id":860,"data":861,"type":218,"tunes":863},"p-ai-1",{"text":862},"AI 代理可以将权限错误转化为一系列操作。如果代理被授予宽泛的 orders.read 工具而没有租户范围的强制执行，推理或提示注入失败可能导致以机器速度进行跨租户读取。",{},{"id":865,"data":866,"type":218,"tunes":868},"p-ai-2",{"text":867},"代理工具描述可以提及租户约束，但强制执行仍必须在受信任的运行时\u002F服务\u002F数据层进行。自然语言指令不是授权边界。",{},{"id":870,"data":871,"type":218,"tunes":873},"p-ai-3",{"text":872},"这同样适用于 RAG：代理可以拥有使用搜索工具的权限，但搜索后端仍必须防止租户 A 的查询返回租户 B 的块。",{},{"id":875,"data":876,"type":42,"tunes":878},"h-tests",{"text":877,"level":247},"分别测试 RBAC 和租户隔离",{},{"id":880,"data":881,"type":391,"tunes":916},"tests-table",{"content":882,"stretched":43,"withHeadings":14},[883,886,889,892,895,898,901,904,907,910,913],[884,885],"测试族","应证明什么",[887,888],"角色降级测试","没有权限的用户即使在自己的租户内也无法执行该操作",[890,891],"跨租户对象测试","拥有正确角色的用户仍无法访问另一租户中相同类型的资源",[893,894],"标识符篡改","更改对象\u002F租户 ID 不会跨越范围",[896,897],"列表\u002F批量端点测试","宽泛查询仅返回已授权的租户数据",[899,900],"缓存重用测试","使用重用进程\u002F连接的两个租户永远不会收到彼此的缓存状态",[902,903],"RLS 请求角色测试","生产请求角色无法绕过行策略",[905,906],"异步工作器测试","租户上下文在排队后仍然存在，并在消费时重新验证",[908,909],"向量检索测试","租户 A 的查询永远不会检索到租户 B 的块",[911,912],"平台管理员测试","跨租户能力是显式、狭窄且可审计的",[914,915],"离职测试","租户数据和派生索引\u002F缓存按策略移除",{},{"id":918,"data":919,"type":218,"tunes":921},"p-tests-1",{"text":920},"OWASP 的授权回归指南特别指出跨租户边界测试，因为缓存、查询或共享服务中的代码更改可能会在角色测试继续通过的情况下悄然破坏隔离。",{},{"id":923,"data":924,"type":42,"tunes":926},"h-failures",{"text":925,"level":247},"常见故障模式",{},{"id":928,"data":929,"type":391,"tunes":973},"failures-table",{"content":930,"stretched":43,"withHeadings":14},[931,934,937,940,943,946,949,952,955,958,961,964,967,970],[932,933],"故障模式","为何失败",[935,936],"检查角色但不检查租户","有效角色变成跨租户权限",[938,939],"信任请求中的租户 ID","客户端控制隔离选择器",[941,942],"限制 UI 但不限制 API","隐藏按钮不能保护后端资源",[944,945],"租户感知的详情端点，未限定范围的列表端点","批量读取泄露其他租户",[947,948],"大多数查询中有租户过滤器","一条被遗忘的路径就会破坏边界",[950,951],"全局缓存键","正确的数据库隔离被缓存数据绕过",[953,954],"共享向量索引且未强制执行元数据过滤器","RAG 检索到另一租户的块",[956,957],"将队列消息中的租户 ID 视为授权","伪造或错误产生的作业可以跨越租户边界",[959,960],"将平台管理员建模为普通 ADMIN","跨租户权力变得隐式且难以审计",[962,963],"角色在租户成员资格之间全局复制","用户在从未被分配的租户中获得权限",[965,966],"独立数据库但共享特权凭据","如果应用程序的凭据过于宽泛，它仍然可以跨数据库访问",[968,969],"RLS 与 BYPASSRLS 请求角色","数据库策略存在，但不保护实际请求路径",[971,972],"将随机 UUID 视为隔离","难以猜测的标识符减少枚举，但不授权访问",{},{"id":975,"data":976,"type":42,"tunes":978},"h-misconceptions",{"text":977,"level":247},"常见误解",{},{"id":980,"data":981,"type":391,"tunes":1016},"misconceptions-table",{"content":982,"stretched":43,"withHeadings":14},[983,986,989,992,995,998,1001,1004,1007,1010,1013],[984,985],"误解","更正",[987,988],"“RBAC 提供租户隔离。”","RBAC 控制权限；隔离还需要租户\u002F资源范围限定。",[990,991],"“如果用户是管理员，则无需租户检查。”","管理员权限仍必须具有明确的范围。",[993,994],"“JWT 中的租户 ID 就足够了。”","只有在验证并一致地应用于每个受保护资源路径时，它才能作为受信任的输入。",[996,997],"“独立数据库消除了授权要求。”","用户仍需要在其租户内的操作级权限。",[999,1000],"“有 tenant_id 列就意味着系统已隔离。”","该字段只有在访问路径强制执行它时才有帮助。",[1002,1003],"“UUID 防止跨租户访问。”","不可预测的标识符是纵深防御，不是授权。",[1005,1006],"“RLS 意味着应用程序代码不需要安全检查。”","应用程序授权、正确的数据库角色和策略覆盖仍然重要。",[1008,1009],"“一个共享向量数据库是不安全的。”","如果隔离可强制执行并经过验证，它可以是安全的；物理分离是一种选择，不是唯一选择。",[1011,1012],"“平台支持需要全局 ADMIN。”","跨租户支持应是一种独特、受限且可审计的权限。",[1014,1015],"“内部服务可以跳过租户检查。”","内部路径仍可能被破坏或配置错误，必须保留租户上下文。",{},{"id":1018,"data":1019,"type":42,"tunes":1021},"h-design",{"text":1020,"level":247},"实用的设计顺序",{},{"id":1023,"data":1024,"type":334,"tunes":1063},"design-flow",{"steps":1025,"title":1062,"orientation":333},[1026,1029,1032,1035,1038,1041,1044,1047,1050,1053,1056,1059],{"label":1027,"description":1028},"1. 定义租户所有权","对哪些实体和资源是全局的、租户范围的、用户范围的或有意跨租户的进行分类。",{"label":1030,"description":1031},"2. 定义操作","为读取、写入、发布、审批、管理和其他业务操作创建显式权限。",{"label":1033,"description":1034},"3. 定义角色","根据职责对权限进行分组，而不嵌入意外的全局范围。",{"label":1036,"description":1037},"4. 定义成员资格范围","将角色分配绑定到其适用的租户\u002F工作区\u002F项目上下文。",{"label":1039,"description":1040},"5. 解析受信任的租户上下文","从经过身份验证、服务器验证的成员资格或服务授权中派生租户身份。",{"label":1042,"description":1043},"6. 强制执行资源所有权","在每个租户拥有的数据\u002F服务边界应用租户范围。",{"label":1045,"description":1046},"7. 添加纵深防御","在风险需要时使用 RLS、独立凭据、模式\u002F数据库、存储策略或策略引擎。",{"label":1048,"description":1049},"8. 将范围传递到派生系统","在缓存、搜索、向量索引、队列、文件和分析中保留租户元数据。",{"label":1051,"description":1052},"9. 显式建模跨租户操作","将平台管理和服务身份与普通租户角色分开。",{"label":1054,"description":1055},"10. 测试两个轴","分别针对缺少权限和错误租户运行负面测试。",{"label":1057,"description":1058},"11. 一起审计租户 + 权限","记录谁在哪个租户、对什么目标、以何种权限执行了操作。",{"label":1060,"description":1061},"12. 在模式\u002F运行时更改后重新测试","引入新表、缓存、队列或检索路径时，隔离可能会被破坏。","将权限和隔离设计为独立维度",{},{"id":1065,"data":1066,"type":42,"tunes":1068},"h-checklist",{"text":1067,"level":247},"RBAC + 租户隔离检查清单",{},{"id":1070,"data":1071,"type":391,"tunes":1117},"checklist-table",{"content":1072,"stretched":43,"withHeadings":14},[1073,1075,1078,1081,1084,1087,1090,1093,1096,1099,1102,1105,1108,1111,1114],[412,1074],"预期答案",[1076,1077],"主体是谁？","经过身份验证的用户\u002F服务\u002F代理身份",[1079,1080],"适用哪个租户上下文？","服务器验证的成员资格或服务范围",[1082,1083],"请求哪个操作？","类型化权限或策略操作",[1085,1086],"主体是否拥有该权限？","角色\u002F策略决策",[1088,1089],"谁拥有目标资源？","显式的租户\u002F全局\u002F用户分类",[1091,1092],"资源范围是否与权限匹配？","租户感知的查找\u002F策略",[1094,1095],"存储能否绕过应用程序检查？","纵深防御决策已记录",[1097,1098],"缓存是否租户安全？","键\u002F命名空间和授权保留租户范围",[1100,1101],"文件\u002FBlob 是否租户安全？","对象策略和签名 URL 签发强制执行范围",[1103,1104],"异步作业是否租户安全？","已验证的上下文传播并重新验证",[1106,1107],"RAG\u002F搜索是否租户安全？","在模型上下文之前强制执行元数据\u002F集合隔离",[1109,1110],"跨租户管理员是否显式？","独立的权限、控制和审计",[1112,1113],"普通凭据能否绕过隔离？","不能，或有严格记录的例外路径",[1115,1116],"跨租户负面测试是否自动化？","是，针对每个相关访问层",{},{"id":1119,"data":1120,"type":42,"tunes":1122},"h-edge",{"text":1121,"level":247},"边界情况与限制",{},{"id":1124,"data":1125,"type":218,"tunes":1127},"p-edge-1",{"text":1126},"一个用户可以属于多个租户。因此，当前租户应当是一个明确的执行上下文，而不是从用户账户中永久推断出来的。",{},{"id":1129,"data":1130,"type":218,"tunes":1132},"p-edge-2",{"text":1131},"有些资源是有意在选定的租户之间共享的，例如协作空间或联盟数据。这需要一个明确的共享模型；假装资源属于某一个租户，然后再添加例外，通常会导致授权变得模糊不清。",{},{"id":1134,"data":1135,"type":218,"tunes":1137},"p-edge-3",{"text":1136},"吵闹邻居隔离与机密性隔离相关但不同。一个租户可能永远看不到另一个租户的数据，但仍然可能耗尽共享的 CPU、队列容量或数据库连接。因此，速率限制和资源配额可以作为可用性边界，按租户进行感知。",{},{"id":1139,"data":1140,"type":218,"tunes":1142},"p-edge-4",{"text":1141},"如果控制平面凭据或管理路径可以跨越边界，物理隔离并不自动安全。如果策略被集中执行、最小权限化并经过充分测试，逻辑隔离也并不自动薄弱。",{},{"id":1144,"data":1145,"type":218,"tunes":1147},"p-edge-5",{"text":1146},"租户隔离要求可能因数据类别而异。公共目录数据、账单记录和私有 AI 文档可能需要在同一个 SaaS 产品内采用不同的存储和加密边界。",{},{"id":1149,"data":1150,"type":42,"tunes":1152},"h-change",{"text":1151,"level":247},"什么会改变这个答案？",{},{"id":1154,"data":1155,"type":218,"tunes":1157},"p-change-1",{"text":1156},"具体实现会随架构而变化：无服务器 API、Kubernetes、PostgreSQL、对象存储、向量数据库和策略引擎暴露出不同的隔离原语。",{},{"id":1159,"data":1160,"type":218,"tunes":1162},"p-change-2",{"text":1161},"所需的强度也会随法规、客户合同、数据敏感性、威胁模型和运营规模而变化。有些租户可能需要隔离的数据库或基础设施，而其他租户则共享池化资源。",{},{"id":1164,"data":1165,"type":218,"tunes":1167},"p-change-3",{"text":1166},"概念上的区别不会改变：执行某项操作的权限与跨越租户边界的权限不是一回事。",{},{"id":1169,"data":1170,"type":42,"tunes":1172},"h-related",{"text":1171,"level":247},"相关规范知识",{},{"id":1174,"data":1175,"type":218,"tunes":1177},"p-related-1",{"text":1176},"S01 是企业 AI 架构和 AI 治理的安全边界前提。一旦 AI 工具、RAG 或代理在多租户数据上运行，租户身份就必须贯穿检索、工具执行、记忆、缓存和审计追踪。",{},{"id":1179,"data":1180,"type":218,"tunes":1182},"p-related-2",{"text":1181},"它也与代理式 AI 直接相关：在代理能够读取或修改业务资源之前，工具能力和角色权限仍然必须受到租户所有权的约束。",{},{"id":1184,"data":1185,"type":1190,"tunes":1191},"ref-agentic",{"url":1186,"title":1187,"excerpt":1188,"ctaLabel":1189},"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fmcp-vs-a2a-vs-ucp-vs-ap2-vs-a2ui-the-agent-protocol-stack-explained","MCP vs A2A vs UCP vs AP2 vs A2UI：代理协议栈详解","协议互操作性不能取代授权或租户隔离。能力发现和业务权限仍然是独立的架构关注点。","阅读协议栈文章","referralArticle",{},{"id":1193,"data":1194,"type":218,"tunes":1196},"p-related-3",{"text":1195},"对于 RAG，必须在受保护的分块进入模型上下文之前强制执行租户隔离。",{},{"id":1198,"data":1199,"type":1190,"tunes":1204},"ref-rag",{"url":1200,"title":1201,"excerpt":1202,"ctaLabel":1203},"https:\u002F\u002Fstajic.de\u002Fzh\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works","什么是 RAG？对其工作原理的最简单解释","理解必须在何处强制执行租户感知的源过滤和向量存储隔离的检索基础。","阅读 RAG 基础",{},{"id":1206,"data":1207,"type":42,"tunes":1209},"h-faq",{"text":1208,"level":247},"常见问题",{},{"id":1211,"data":1212,"type":1211,"tunes":1251},"faq",{"items":1213,"title":1250},[1214,1218,1222,1226,1230,1234,1238,1242,1246],{"id":1215,"answer":1216,"question":1217},"faq1","RBAC 决定主体可以执行哪些操作。租户隔离决定这些操作可以访问哪个租户的资源。安全的多租户应用程序通常需要两者兼备。","RBAC 和租户隔离有什么区别？",{"id":1219,"answer":1220,"question":1221},"faq2","不。ADMIN 应当具有明确的范围。租户管理员通常只在该租户内拥有广泛权限，而跨租户的平台管理应当单独建模。","ADMIN 角色是否自动允许访问所有租户？",{"id":1223,"answer":1224,"question":1225},"faq3","不。身份验证证明身份。授权控制允许的操作。租户隔离还额外防止这些操作触及错误租户的资源。","仅靠身份验证就足以实现租户隔离吗？",{"id":1227,"answer":1228,"question":1229},"faq4","它可以作为租户上下文的输入之一，但服务器必须验证当前成员资格\u002F权限，并在受保护资源边界处强制执行范围。仅凭声明不能取代隔离控制。","tenantId 应该存储在 JWT 中吗？",{"id":1231,"answer":1232,"question":1233},"faq5","不一定。共享表、RLS、模式、数据库、基础设施和混合隔离模型都可能有效，具体取决于风险和运营要求。","我需要为每个租户使用单独的数据库吗？",{"id":1235,"answer":1236,"question":1237},"faq6","RLS 可以提供强大的纵深防御，但正确的数据库角色、请求上下文、策略覆盖范围和应用程序级授权仍然很重要。","PostgreSQL RLS 可以取代应用程序代码中的租户过滤器吗？",{"id":1239,"answer":1240,"question":1241},"faq7","应在检索期间强制执行租户\u002F访问范围，以便未经授权的分块永远不会进入模型上下文。在分块和索引过程中保留访问元数据。","RAG 应如何强制执行租户隔离？",{"id":1243,"answer":1244,"question":1245},"faq8","可以。这在 B2B SaaS 中很常见，也是将角色分配按租户成员资格进行范围限定的有力理由，而不是将角色视为全局附加到用户。","一个用户可以在不同租户中拥有不同角色吗？",{"id":1247,"answer":1248,"question":1249},"faq9","使用负向跨租户测试：创建至少两个租户，在一个租户中为用户授予有效权限，然后证明每个受保护路径都拒绝对另一个租户资源的访问。","测试租户隔离的最佳方法是什么？","RBAC 与租户隔离常见问题",{},{"id":1253,"data":1254,"type":42,"tunes":1256},"h-glossary",{"text":1255,"level":247},"术语表",{},{"id":1258,"data":1259,"type":1258,"tunes":1306},"glossary",{"title":1260,"entries":1261},"关键多租户安全术语",[1262,1264,1267,1270,1274,1278,1282,1286,1290,1294,1298,1302],{"term":395,"anchor":394,"definition":1263},"基于角色的访问控制：一种授权模型，将权限与角色关联，并将用户或主体分配到这些角色。",{"term":1265,"anchor":397,"definition":1266},"租户","共享多租户系统中的客户、组织、工作区或其他隔离的逻辑消费者。",{"term":398,"anchor":1268,"definition":1269},"tenant-isolation","防止一个租户在共享系统中访问、修改或接收另一个租户资源的机制。",{"term":1271,"anchor":1272,"definition":1273},"身份验证","authentication","验证用户、服务或其他主体身份的过程。",{"term":1275,"anchor":1276,"definition":1277},"授权","authorization","确定主体是否可以对资源执行所请求操作的决策过程。",{"term":1279,"anchor":1280,"definition":1281},"权限","permission","已定义的允许操作或能力，例如 orders.read 或 users.write。",{"term":1283,"anchor":1284,"definition":1285},"角色","role","与职责或职能相关联的权限的命名分组。",{"term":1287,"anchor":1288,"definition":1289},"ABAC","abac","基于属性的访问控制：基于主体、资源、操作或环境属性的授权。",{"term":1291,"anchor":1292,"definition":1293},"行级安全","row-level-security","数据库策略机制，限制数据库角色或会话可以读取或修改哪些行。",{"term":1295,"anchor":1296,"definition":1297},"跨租户访问","cross-tenant-access","在一个租户上下文中运行的主体访问属于另一个租户资源的任何访问路径。",{"term":1299,"anchor":1300,"definition":1301},"平台管理员","platform-administrator","具有明确建模权限的特权操作身份，可能跨越多个租户。",{"term":1303,"anchor":1304,"definition":1305},"租户上下文","tenant-context","当前请求、作业或代理操作执行时所处的已验证租户范围。",{},{"id":1308,"data":1309,"type":42,"tunes":1311},"h-conclusion",{"text":1310,"level":247},"结论",{},{"id":1313,"data":1314,"type":218,"tunes":1316},"p-conclusion-1",{"text":1315},"RBAC 和租户隔离是互补的安全机制，而非相互竞争。RBAC 构建操作权限；租户隔离约束该权限可以适用的资源边界。",{},{"id":1318,"data":1319,"type":218,"tunes":1321},"p-conclusion-2",{"text":1320},"因此，一个健壮的多租户请求需要的不仅仅是“用户拥有 ADMIN 角色”。它需要已验证的主体、已验证的租户上下文、允许的操作、租户范围内的目标，以及在每个可能承载租户数据的资源层上执行强制措施。",{},{"id":1323,"data":1324,"type":218,"tunes":1326},"p-conclusion-3",{"text":1325},"最简短可靠的规则是：授权操作，然后隔离范围——并且永远不要假设其中一个能证明另一个。",{},{"id":1328,"data":1329,"type":42,"tunes":1331},"h-sources",{"text":1330,"level":247},"主要来源和当前指南",{},{"id":1333,"data":1334,"type":218,"tunes":1336},"p-sources-note",{"text":1335},"以下来源支持 RBAC 定义和当前租户隔离指南。Aaasaasa AI CMS 部分是原始实现证据，并有意限定在已验证的代码模式范围内。",{},{"id":1338,"data":1339,"type":1345,"tunes":1346},"src-nist-rbac",{"link":1340,"meta":1341},"https:\u002F\u002Fcsrc.nist.gov\u002Fprojects\u002Frole-based-access-control",{"image":1342,"title":1343,"description":1344},{"url":369},"NIST — 基于角色的访问控制","NIST 对 RBAC 模型和 INCITS RBAC 标准的概述，包括用户、角色、权限、操作和对象。","linkTool",{},{"id":1348,"data":1349,"type":1345,"tunes":1355},"src-nist-glossary",{"link":1350,"meta":1351},"https:\u002F\u002Fcsrc.nist.gov\u002Fglossary\u002Fterm\u002Frole_based_access_control",{"image":1352,"title":1353,"description":1354},{"url":369},"NIST CSRC — RBAC 术语表","NIST 当前术语表对基于角色的访问控制的定义，即通过角色进行权限分配。",{},{"id":1357,"data":1358,"type":1345,"tunes":1364},"src-aws-isolation",{"link":1359,"meta":1360},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fwhitepapers\u002Flatest\u002Fsaas-tenant-isolation-strategies\u002Fthe-isolation-mindset.html",{"image":1361,"title":1362,"description":1363},{"url":369},"AWS — 隔离思维模式","AWS SaaS 指南明确区分身份验证\u002F授权与租户隔离，并推荐共享隔离机制。",{},{"id":1366,"data":1367,"type":1345,"tunes":1373},"src-aws-faq",{"link":1368,"meta":1369},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fprescriptive-guidance\u002Flatest\u002Fsaas-multitenant-api-access-authorization\u002Ffaq.html",{"image":1370,"title":1371,"description":1372},{"url":369},"AWS — 多租户授权常见问题","当前指南解释 SaaS 应用程序中授权与租户隔离之间的区别。",{},{"id":1375,"data":1376,"type":1345,"tunes":1382},"src-aws-avp",{"link":1377,"meta":1378},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fprescriptive-guidance\u002Flatest\u002Fsaas-multitenant-api-access-authorization\u002Favp-design-considerations.html",{"image":1379,"title":1380,"description":1381},{"url":369},"AWS — 多租户设计考虑因素","当前 SaaS 指南区分租户隔离与授权，并讨论池化\u002F隔离授权策略模型。",{},{"id":1384,"data":1385,"type":1345,"tunes":1391},"src-owasp-multi",{"link":1386,"meta":1387},"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FMulti_Tenant_Security_Cheat_Sheet.html",{"image":1388,"title":1389,"description":1390},{"url":369},"OWASP — 多租户应用程序安全备忘单","当前关于租户上下文、数据库隔离、缓存、存储、队列、测试和跨租户访问预防的实用指南。",{},{"id":1393,"data":1394,"type":1345,"tunes":1400},"src-owasp-rag",{"link":1395,"meta":1396},"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FRAG_Security_Cheat_Sheet.html",{"image":1397,"title":1398,"description":1399},{"url":369},"OWASP — RAG 安全备忘单","当前指南要求在检索时进行访问控制，并为多租户向量存储提供租户隔离。",{},{"id":1402,"data":1403,"type":1345,"tunes":1409},"src-owasp-auth-test",{"link":1404,"meta":1405},"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FAuthorization_Regression_Testing_Cheat_Sheet.html",{"image":1406,"title":1407,"description":1408},{"url":369},"OWASP — 授权回归测试","当前测试指南，包括角色降级和跨租户边界测试。",{},"2.31","RBAC 控制用户可以做什么；租户隔离控制该操作可以触及哪个租户的资源。了解为什么多租户 SaaS 安全需要这两道边界。","\u002Fuploads\u002F2026\u002F10\u002Frbac-vs-tenant-isolation-two-different-security-boundaries-1791485111528-qqtzby.webp","rbac-vs-tenant-isolation-two-different-security-boundaries-1791485111528-qqtzby","PUBLISHED","2026-10-08T14:43:00.000Z","2026-10-08T18:43:57.878Z","2026-10-08T18:56:28.335Z",{"en":1419,"de":1420,"sr":1421,"es":1422,"fr":1423,"it":1424,"ru":1425,"zh":1426},"\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Fde\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Fsr\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Fes\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Ffr\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Fit\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Fru\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries","\u002Fzh\u002Fblog\u002Frbac-vs-tenant-isolation-two-different-security-boundaries",[1428,1432,1436],{"id":1429,"name":1430,"slug":1431},84,"策略与数据边界","policy-and-data",{"id":1433,"name":1434,"slug":1435},57,"数据边界","data-boundaries",{"id":1437,"name":1438,"slug":1439},64,"信息架构","information-architecture",{"id":1441,"login":1442,"email":1443,"displayName":1444},"20","rooth8233","aleksandar@stajic.de","Aleksandar Stajić",[1446,2443],{"lang":1447,"title":1448,"content":1449,"contentJson":1450,"excerpt":2442},"en","RBAC vs Tenant Isolation: Two Different Security Boundaries","{\"time\":1791485112883,\"blocks\":[{\"id\":\"intro\",\"type\":\"paragraph\",\"data\":{\"text\":\"RBAC and tenant isolation solve two different security problems in multi-tenant systems. Role-Based Access Control (RBAC) determines what an authenticated principal is allowed to do, such as read orders, edit products or manage users. Tenant isolation determines which tenant's data, resources and execution context that principal is allowed to access. A user can be correctly authenticated and correctly assigned an RBAC role yet still experience a security failure if the application lets that role operate on another tenant's resources.\"},\"tunes\":{}},{\"id\":\"direct\",\"type\":\"callout\",\"data\":{\"variant\":\"info\",\"title\":\"Direct answer\",\"body\":\"\u003Cstrong>RBAC answers “what may this identity do?” Tenant isolation answers “inside whose boundary may it do it?”\u003C\u002Fstrong>\u003Cbr>\u003Cbr>A secure multi-tenant application normally needs both. A tenant administrator may have broad permissions, but those permissions should remain constrained to the administrator's tenant unless an explicitly separate platform-level authority exists.\"},\"tunes\":{}},{\"id\":\"boundary\",\"type\":\"callout\",\"data\":{\"variant\":\"warning\",\"title\":\"A role is not a tenant boundary\",\"body\":\"Giving a user the role \u003Ccode>ADMIN\u003C\u002Fcode> does not automatically imply “administrator of tenant A only.” The role must be evaluated together with verified tenant context and the target resource's tenant ownership. Otherwise a valid role can become a cross-tenant privilege.\"},\"tunes\":{}},{\"id\":\"current\",\"type\":\"callout\",\"data\":{\"variant\":\"note\",\"title\":\"Current-source note — 8 October 2026\",\"body\":\"The underlying distinction is stable. NIST defines RBAC around users, roles, permissions, operations and objects. Current AWS SaaS guidance explicitly states that authentication and authorization are not equal to tenant isolation, and that a user can be authenticated and authorized while still accessing another tenant's resources if isolation is not separately enforced. OWASP's current Multi-Tenant Security guidance likewise treats tenant isolation as a cross-layer requirement covering APIs, databases, caches, storage, queues and other shared resources.\"},\"tunes\":{}},{\"id\":\"toc\",\"type\":\"tableOfContents\",\"data\":{\"title\":\"Contents\",\"minLevel\":2,\"maxLevel\":3},\"tunes\":{}},{\"id\":\"h-meaning\",\"type\":\"header\",\"data\":{\"text\":\"What RBAC really controls\",\"level\":2},\"tunes\":{}},{\"id\":\"p-rbac-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"RBAC is an authorization model in which permissions are associated with roles and users are assigned to those roles. The role acts as an administrative abstraction between identities and permissions.\"},\"tunes\":{}},{\"id\":\"p-rbac-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"NIST's classic RBAC work formalizes this around users, roles, permissions, operations and objects. The practical benefit is that an organization can manage authorization through relatively stable job or responsibility roles rather than attaching every permission directly to every user.\"},\"tunes\":{}},{\"id\":\"p-rbac-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"A role such as EDITOR can therefore mean: may read content, write content and publish content. A role such as ACCOUNTANT may mean: may read billing data, reconcile invoices and approve settlements.\"},\"tunes\":{}},{\"id\":\"h-tenant\",\"type\":\"header\",\"data\":{\"text\":\"What tenant isolation really controls\",\"level\":2},\"tunes\":{}},{\"id\":\"p-tenant-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Tenant isolation is the set of mechanisms that prevents one tenant from reading, modifying, influencing or accidentally receiving another tenant's resources in a shared system.\"},\"tunes\":{}},{\"id\":\"p-tenant-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"The protected boundary is broader than database rows. Tenant-specific state can exist in relational tables, object storage, vector indexes, caches, search indexes, queue messages, files, temporary artifacts, background jobs, analytics, rate limits and infrastructure resources.\"},\"tunes\":{}},{\"id\":\"p-tenant-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"AWS's SaaS guidance makes the distinction explicit: authorization grants access to resources, while tenant isolation ensures those resources cannot cross the wrong tenant boundary even when infrastructure is shared.\"},\"tunes\":{}},{\"id\":\"h-simple\",\"type\":\"header\",\"data\":{\"text\":\"The simplest example\",\"level\":2},\"tunes\":{}},{\"id\":\"p-simple-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Suppose Alice is an administrator for Tenant A and Bob is an administrator for Tenant B. Both users legitimately hold the same ADMIN role.\"},\"tunes\":{}},{\"id\":\"p-simple-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"RBAC can correctly conclude that both users may execute an operation such as users.read. But when Alice requests user ID 847, the application must still verify that user 847 belongs to Tenant A.\"},\"tunes\":{}},{\"id\":\"p-simple-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"If the API checks only “Alice has ADMIN” and then executes SELECT * FROM users WHERE id = 847, RBAC succeeded while tenant isolation failed.\"},\"tunes\":{}},{\"id\":\"simple-flow\",\"type\":\"processFlow\",\"data\":{\"title\":\"A correct multi-tenant authorization decision\",\"orientation\":\"auto\",\"steps\":[{\"label\":\"1. Authenticate principal\",\"description\":\"Establish who the user, service or agent is.\"},{\"label\":\"2. Resolve verified tenant context\",\"description\":\"Determine which tenant context applies from trusted server-side identity\u002Fmembership information.\"},{\"label\":\"3. Resolve permission\",\"description\":\"Evaluate whether the principal's role or policy permits the requested operation.\"},{\"label\":\"4. Scope the target resource\",\"description\":\"Verify that the target object belongs to the permitted tenant or explicitly shared scope.\"},{\"label\":\"5. Enforce at the access boundary\",\"description\":\"Perform the database, cache, storage, queue or service operation with tenant constraints applied.\"},{\"label\":\"6. Audit both dimensions\",\"description\":\"Record principal, tenant, operation, target and result so cross-tenant attempts are visible.\"}]},\"tunes\":{}},{\"id\":\"h-stops\",\"type\":\"header\",\"data\":{\"text\":\"Where the simple example stops\",\"level\":2},\"tunes\":{}},{\"id\":\"p-stops-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Real systems often contain several classes of identity: tenant users, platform administrators, background workers, integrations, agents and cross-tenant operational services. Some of these legitimately cross tenant boundaries.\"},\"tunes\":{}},{\"id\":\"p-stops-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"That does not remove the need for isolation. It means cross-tenant authority must be explicit, narrow and separately auditable rather than emerging accidentally from a global role or unscoped database connection.\"},\"tunes\":{}},{\"id\":\"p-stops-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Tenant isolation can also vary by layer. A product may share application servers while separating databases, or use a shared database with row-level policies while giving premium tenants isolated storage or compute. There is no single universal isolation topology.\"},\"tunes\":{}},{\"id\":\"h-compare\",\"type\":\"header\",\"data\":{\"text\":\"RBAC vs tenant isolation\",\"level\":2},\"tunes\":{}},{\"id\":\"core-comparison\",\"type\":\"comparison\",\"data\":{\"title\":\"Two different security dimensions\",\"layout\":\"table\",\"columns\":[{\"id\":\"rbac\",\"label\":\"RBAC\"},{\"id\":\"tenant\",\"label\":\"Tenant isolation\"}],\"rows\":[{\"id\":\"question\",\"label\":\"Primary question\",\"values\":[\"\",\"\"]},{\"id\":\"unit\",\"label\":\"Typical unit\",\"values\":[\"\",\"\"]},{\"id\":\"example\",\"label\":\"Example\",\"values\":[\"\",\"\"]},{\"id\":\"failure\",\"label\":\"Typical failure\",\"values\":[\"\",\"\"]},{\"id\":\"implementation\",\"label\":\"Typical implementation\",\"values\":[\"\",\"\"]},{\"id\":\"scope\",\"label\":\"Can it exist alone?\",\"values\":[\"\",\"\"]}]},\"tunes\":{}},{\"id\":\"h-authn\",\"type\":\"header\",\"data\":{\"text\":\"Authentication, authorization and isolation are three different checks\",\"level\":2},\"tunes\":{}},{\"id\":\"three-checks\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Layer\",\"Question\",\"Example failure\"],[\"Authentication\",\"Who is this principal?\",\"Attacker impersonates Alice\"],[\"Authorization \u002F RBAC\",\"May this principal perform this operation?\",\"Viewer can delete users\"],[\"Tenant isolation\",\"May this operation reach this tenant\u002Fresource boundary?\",\"Tenant A admin reads Tenant B order\"]]},\"tunes\":{}},{\"id\":\"p-authn-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"These checks are related but non-substitutable. Authentication can be perfect while authorization fails. Authorization can be correct while tenant isolation fails. A secure SaaS request path needs all applicable boundaries.\"},\"tunes\":{}},{\"id\":\"h-role-scope\",\"type\":\"header\",\"data\":{\"text\":\"Roles need a scope\",\"level\":2},\"tunes\":{}},{\"id\":\"p-role-scope-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"The word ADMIN is incomplete without scope. It can mean platform administrator, tenant administrator, project administrator, workspace administrator or administrator of one subsystem.\"},\"tunes\":{}},{\"id\":\"p-role-scope-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"In multi-tenant systems, role assignment should normally be associated with tenant membership or another explicit resource scope. The same user may legitimately be ADMIN in Tenant A and VIEWER in Tenant B.\"},\"tunes\":{}},{\"id\":\"p-role-scope-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"A global role model that ignores this distinction can create privilege leakage even when the permission map itself is correct.\"},\"tunes\":{}},{\"id\":\"h-context\",\"type\":\"header\",\"data\":{\"text\":\"Tenant context must come from a trusted path\",\"level\":2},\"tunes\":{}},{\"id\":\"p-context-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"A tenant ID supplied by the client is useful as a selector, but it is not proof of authority. The server must derive or verify tenant membership against authenticated identity and current authorization data.\"},\"tunes\":{}},{\"id\":\"p-context-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"OWASP's current multi-tenant guidance recommends establishing tenant context early in the request lifecycle and explicitly warns against treating client headers or request parameters as authorization proof.\"},\"tunes\":{}},{\"id\":\"p-context-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"This matters because a trivial request modification from tenant=A to tenant=B must not be sufficient to cross the isolation boundary.\"},\"tunes\":{}},{\"id\":\"h-query\",\"type\":\"header\",\"data\":{\"text\":\"Tenant scope belongs in the resource lookup\",\"level\":2},\"tunes\":{}},{\"id\":\"p-query-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"A common application-level isolation pattern is to include tenant scope in the same query that resolves the resource.\"},\"tunes\":{}},{\"id\":\"query-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Weak lookup\",\"Stronger tenant-scoped lookup\"],[\"findFirst({ where: { id } })\",\"findFirst({ where: { id, tenantId } })\"],[\"UPDATE orders SET ... WHERE id = ?\",\"UPDATE orders SET ... WHERE id = ? AND tenant_id = ?\"],[\"cache.get('user:' + id)\",\"cache.get('tenant:' + tenantId + ':user:' + id)\"]]},\"tunes\":{}},{\"id\":\"p-query-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"This pattern is not the only possible isolation mechanism, but it keeps tenant ownership close to the data access operation and prevents an object ID from becoming a cross-tenant capability.\"},\"tunes\":{}},{\"id\":\"h-defense\",\"type\":\"header\",\"data\":{\"text\":\"Application checks are useful, but isolation should not depend on perfect developer behavior\",\"level\":2},\"tunes\":{}},{\"id\":\"p-defense-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"AWS's isolation guidance explicitly warns against leaving isolation enforcement only to service developers. In a large codebase, eventually one query, cache key or worker path may omit tenant scope.\"},\"tunes\":{}},{\"id\":\"p-defense-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Defense in depth can therefore move isolation into shared middleware, repository\u002Fservice layers, policy engines, database Row-Level Security, dedicated credentials, separate schemas or separate databases depending on risk and architecture.\"},\"tunes\":{}},{\"id\":\"defense-rule\",\"type\":\"callout\",\"data\":{\"variant\":\"success\",\"title\":\"Isolation should be hard to forget\",\"body\":\"The strongest boundary is one that ordinary application code cannot casually bypass by omitting one \u003Ccode>tenantId\u003C\u002Fcode> condition.\"},\"tunes\":{}},{\"id\":\"h-db\",\"type\":\"header\",\"data\":{\"text\":\"Database isolation strategies\",\"level\":2},\"tunes\":{}},{\"id\":\"db-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Strategy\",\"Boundary\",\"Strength \u002F trade-off\"],[\"Shared tables + tenant key\",\"Row\u002Fapplication policy\",\"Operationally efficient; requires exhaustive tenant scoping and strong tests\"],[\"Shared tables + database RLS\",\"Database policy boundary\",\"Reduces dependence on every application query; requires correct roles, session\u002Ftransaction tenant context and policy coverage\"],[\"Separate schemas\",\"Namespace \u002F DB-role boundary\",\"Stronger logical separation; more operational complexity\"],[\"Separate databases\",\"Database \u002F credential boundary\",\"Strong isolation and simpler blast-radius story; higher provisioning and operations cost\"],[\"Separate infrastructure\u002Faccount\",\"Infrastructure boundary\",\"Strongest coarse-grained separation; highest cost and operational overhead\"],[\"Hybrid\",\"Per workload\u002Fdata class\",\"Allows stronger isolation only where risk\u002Fcompliance justifies it\"]]},\"tunes\":{}},{\"id\":\"p-db-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"OWASP's current Multi-Tenant Security Cheat Sheet lists separate databases, separate schemas, shared tables with row-level controls and hybrid models. The correct model depends on threat level, compliance, performance and operational cost.\"},\"tunes\":{}},{\"id\":\"h-rls\",\"type\":\"header\",\"data\":{\"text\":\"PostgreSQL Row-Level Security can provide defense in depth\",\"level\":2},\"tunes\":{}},{\"id\":\"p-rls-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"With shared tables, PostgreSQL Row-Level Security can enforce a tenant predicate at the database layer so ordinary queries cannot see rows outside the active tenant policy.\"},\"tunes\":{}},{\"id\":\"p-rls-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"However, RLS is not magic. PostgreSQL superusers and roles with BYPASSRLS can bypass row policies. OWASP therefore recommends using a least-privileged request-path role and testing the same connection\u002Fpooling mode used in production.\"},\"tunes\":{}},{\"id\":\"p-rls-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Connection reuse is another important edge: tenant context must be set and reset safely for every transaction\u002Frequest so one pooled connection cannot leak prior tenant state.\"},\"tunes\":{}},{\"id\":\"h-cache\",\"type\":\"header\",\"data\":{\"text\":\"Tenant isolation must include caches\",\"level\":2},\"tunes\":{}},{\"id\":\"p-cache-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"A database query can be perfectly scoped and still leak data through a shared cache key.\"},\"tunes\":{}},{\"id\":\"p-cache-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"If user:42 exists in both Tenant A and Tenant B, a global cache key can return the wrong tenant's value. Tenant-sensitive cache keys should include every attribute that changes visibility or result semantics, commonly tenant, user, locale, feature set or permission version.\"},\"tunes\":{}},{\"id\":\"p-cache-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Cache partitioning is defense in depth, not a replacement for authorization. The request still needs to be authorized before protected cached content is returned.\"},\"tunes\":{}},{\"id\":\"h-storage\",\"type\":\"header\",\"data\":{\"text\":\"Files and object storage need their own tenant boundary\",\"level\":2},\"tunes\":{}},{\"id\":\"p-storage-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Object storage should distinguish global, tenant-scoped and user-scoped objects. A folder prefix alone is only a naming convention unless access policy actually constrains reads and writes.\"},\"tunes\":{}},{\"id\":\"p-storage-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Stronger designs may use tenant-aware object keys, bucket policies, separate buckets\u002Faccounts or tenant-specific encryption keys where risk or compliance requires stronger isolation.\"},\"tunes\":{}},{\"id\":\"p-storage-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Signed URLs must be authorized before issuance and scoped to the exact object and operation. Possession of an object identifier should not itself grant cross-tenant access.\"},\"tunes\":{}},{\"id\":\"h-queues\",\"type\":\"header\",\"data\":{\"text\":\"Background jobs and queues can break isolation\",\"level\":2},\"tunes\":{}},{\"id\":\"p-queue-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Async jobs often leave the original HTTP request context, which makes tenant propagation easy to mishandle. A queue message containing tenantId is not sufficient proof that the producer was authorized.\"},\"tunes\":{}},{\"id\":\"p-queue-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"The worker should carry a verified service\u002Fuser identity or trusted job envelope, re-establish tenant context and re-authorize consequential operations at the consumer boundary.\"},\"tunes\":{}},{\"id\":\"p-queue-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Tenant isolation also includes availability. One tenant should not be able to monopolize shared workers, queues, connection pools or compute in ways that materially degrade other tenants.\"},\"tunes\":{}},{\"id\":\"h-search\",\"type\":\"header\",\"data\":{\"text\":\"Search and RAG need tenant-aware retrieval\",\"level\":2},\"tunes\":{}},{\"id\":\"p-search-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Multi-tenant AI introduces another copy of the isolation problem. Documents may be chunked, embedded and stored in a vector index after ingestion.\"},\"tunes\":{}},{\"id\":\"p-search-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"OWASP's current RAG security guidance states that access control must be enforced at retrieval time and that chunks from Tenant A must not be retrieved by queries from Tenant B. Document-level permissions cannot simply be assumed to survive chunking automatically.\"},\"tunes\":{}},{\"id\":\"p-search-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"The vector index therefore needs tenant\u002Faccess metadata or physically\u002Flogically separate collections according to the isolation design. Retrieval filters should be applied before unauthorized content can enter model context.\"},\"tunes\":{}},{\"id\":\"rag-rule\",\"type\":\"callout\",\"data\":{\"variant\":\"warning\",\"title\":\"The model must never be the tenant filter\",\"body\":\"Do not retrieve cross-tenant chunks and then instruct the language model to ignore them. Once protected data enters model context, the isolation boundary has already failed.\"},\"tunes\":{}},{\"id\":\"h-derived\",\"type\":\"header\",\"data\":{\"text\":\"Derived data inherits tenant sensitivity\",\"level\":2},\"tunes\":{}},{\"id\":\"p-derived-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Embeddings, search indexes, thumbnails, generated summaries, caches, analytics rows and AI responses are derived from source data. Their tenant scope should follow the source unless an explicit transformation creates a legitimate shared\u002Fglobal artifact.\"},\"tunes\":{}},{\"id\":\"p-derived-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Deletion and offboarding must therefore propagate beyond the canonical row. Removing a tenant document while leaving searchable chunks or cached summaries can retain cross-tenant or post-retention exposure.\"},\"tunes\":{}},{\"id\":\"h-shared\",\"type\":\"header\",\"data\":{\"text\":\"Not everything belongs to a tenant\",\"level\":2},\"tunes\":{}},{\"id\":\"p-shared-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Multi-tenant platforms often have intentionally global resources: product taxonomies, public templates, system permissions, feature definitions or public content.\"},\"tunes\":{}},{\"id\":\"p-shared-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"The safest model is explicit classification: global, tenant-scoped, user-scoped or explicitly cross-tenant. Ambiguous resources are where accidental leakage begins.\"},\"tunes\":{}},{\"id\":\"p-shared-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"An intentionally shared object should have a documented reason for being global rather than simply lacking a tenant association.\"},\"tunes\":{}},{\"id\":\"h-platform-admin\",\"type\":\"header\",\"data\":{\"text\":\"Platform administrators require a different authority model\",\"level\":2},\"tunes\":{}},{\"id\":\"p-platform-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"A platform operator may need to inspect multiple tenants for support, compliance or infrastructure operations. Modeling this as an ordinary tenant ADMIN with accidental global database access weakens both security and auditability.\"},\"tunes\":{}},{\"id\":\"p-platform-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"A better design uses a distinct platform identity or explicit cross-tenant permission, stronger authentication, purpose limitation, detailed audit and, where appropriate, approval or break-glass controls.\"},\"tunes\":{}},{\"id\":\"p-platform-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Cross-tenant access should therefore be a named capability, not the absence of a tenant filter.\"},\"tunes\":{}},{\"id\":\"h-abac\",\"type\":\"header\",\"data\":{\"text\":\"RBAC can be combined with attributes\",\"level\":2},\"tunes\":{}},{\"id\":\"p-abac-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"Some decisions depend on more than role. Tenant membership, region, resource owner, subscription tier, time, project membership or data classification can all affect access.\"},\"tunes\":{}},{\"id\":\"p-abac-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"RBAC and ABAC are not mutually exclusive. AWS's current multi-tenant authorization guidance discusses RBAC, ABAC and hybrid models. A role can define broad responsibility while attributes constrain which concrete resource instance can be accessed.\"},\"tunes\":{}},{\"id\":\"p-abac-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"The key architecture rule remains: do not encode tenant isolation only as an incidental role name if tenant identity is a first-class resource boundary.\"},\"tunes\":{}},{\"id\":\"h-matrix\",\"type\":\"header\",\"data\":{\"text\":\"Authorization decisions are at least two-dimensional\",\"level\":2},\"tunes\":{}},{\"id\":\"matrix-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Principal\",\"Role permission\",\"Tenant relationship\",\"Decision\"],[\"Alice\",\"orders.read\",\"Order belongs to Alice's tenant\",\"Allow\"],[\"Alice\",\"orders.read\",\"Order belongs to another tenant\",\"Deny\"],[\"Alice\",\"orders.write\",\"Order belongs to Alice's tenant\",\"Allow if role includes write\"],[\"Alice\",\"orders.write\",\"Order belongs to another tenant\",\"Deny\"],[\"Platform support\",\"support.cross_tenant.read\",\"Explicit support scope + audited target tenant\",\"Potentially allow under platform policy\"],[\"Background worker\",\"orders.process\",\"Trusted service scope for job tenant\",\"Allow only for verified job tenant\"]]},\"tunes\":{}},{\"id\":\"h-implementation\",\"type\":\"header\",\"data\":{\"text\":\"Original implementation evidence: Aaasaasa AI CMS\",\"level\":2},\"tunes\":{}},{\"id\":\"impl-note\",\"type\":\"callout\",\"data\":{\"variant\":\"note\",\"title\":\"Original implementation evidence\",\"body\":\"Aaasaasa AI CMS contains a concrete tenant-scoped RBAC implementation. It is useful evidence for how role authorization and tenant scope can be combined, but it should not be presented as proof that every storage, cache or infrastructure layer has complete tenant isolation.\"},\"tunes\":{}},{\"id\":\"p-impl-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"The RBAC service defines typed permission codes such as cms.content.read, shop.orders.write, billing.reconcile and users.roles. System roles map those permissions into named responsibility sets.\"},\"tunes\":{}},{\"id\":\"p-impl-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Role records are created and resolved with a tenantId. System roles are upserted using a composite tenant\u002Fcode identity, and role listing is filtered by tenant.\"},\"tunes\":{}},{\"id\":\"p-impl-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Role update and deletion first resolve the role using both role ID and tenant ID. User-role assignments are also stored and replaced under the current tenant context.\"},\"tunes\":{}},{\"id\":\"p-impl-4\",\"type\":\"paragraph\",\"data\":{\"text\":\"Permission resolution reads explicit user-role assignments scoped by both tenantId and userId. This prevents one tenant's role assignment from automatically becoming another tenant's role assignment.\"},\"tunes\":{}},{\"id\":\"p-impl-5\",\"type\":\"paragraph\",\"data\":{\"text\":\"At API level, administrative RBAC routes resolve a tenant context before creating or modifying roles. This is the correct direction: permission administration itself must respect tenancy.\"},\"tunes\":{}},{\"id\":\"impl-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Observed implementation pattern\",\"Security meaning\"],[\"Typed permission codes\",\"RBAC operation vocabulary is explicit\"],[\"System role → permission maps\",\"Roles aggregate permissions rather than hard-coding users\"],[\"tenantId_code role identity\",\"Same logical role can exist separately per tenant\"],[\"Role lookup uses id + tenantId\",\"Role mutation is tenant-scoped\"],[\"User-role relation stores tenantId\",\"Membership is not globally inferred from role alone\"],[\"Permission resolution uses tenantId + userId\",\"Authorization is evaluated inside tenant context\"]]},\"tunes\":{}},{\"id\":\"impl-boundary\",\"type\":\"callout\",\"data\":{\"variant\":\"warning\",\"title\":\"What this evidence does not prove\",\"body\":\"Tenant-scoped RBAC is one layer. Complete tenant isolation must also cover all tenant-owned resource lookups, databases, caches, files, search\u002Fvector indexes, background jobs, integrations and operational paths. The repository evidence here supports the RBAC\u002Ftenant-scope design pattern, not a claim of independently audited SaaS isolation.\"},\"tunes\":{}},{\"id\":\"h-ai\",\"type\":\"header\",\"data\":{\"text\":\"Why this distinction matters even more for AI agents\",\"level\":2},\"tunes\":{}},{\"id\":\"p-ai-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"AI agents can turn a permission mistake into a sequence of actions. If an agent is given a broad orders.read tool without tenant-scoped enforcement, a reasoning or prompt-injection failure can cause cross-tenant reads at machine speed.\"},\"tunes\":{}},{\"id\":\"p-ai-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Agent tool descriptions can mention tenant constraints, but enforcement must still happen in the trusted runtime\u002Fservice\u002Fdata layer. Natural-language instructions are not an authorization boundary.\"},\"tunes\":{}},{\"id\":\"p-ai-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"The same applies to RAG: an agent can have permission to use the search tool while the search backend must still prevent Tenant A's query from returning Tenant B's chunks.\"},\"tunes\":{}},{\"id\":\"h-tests\",\"type\":\"header\",\"data\":{\"text\":\"Test RBAC and tenant isolation separately\",\"level\":2},\"tunes\":{}},{\"id\":\"tests-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Test family\",\"What it should prove\"],[\"Role demotion test\",\"A user without a permission cannot perform the operation even inside their own tenant\"],[\"Cross-tenant object test\",\"A user with the correct role still cannot access the same resource type in another tenant\"],[\"Identifier tampering\",\"Changing object\u002Ftenant IDs does not cross scope\"],[\"List\u002Fbulk endpoint test\",\"Broad queries return only authorized tenant data\"],[\"Cache reuse test\",\"Two tenants using reused processes\u002Fconnections never receive each other's cached state\"],[\"RLS request-role test\",\"Production request role cannot bypass row policies\"],[\"Async worker test\",\"Tenant context survives queueing and is revalidated at consumption\"],[\"Vector retrieval test\",\"Tenant A query never retrieves Tenant B chunks\"],[\"Platform-admin test\",\"Cross-tenant capability is explicit, narrow and auditable\"],[\"Offboarding test\",\"Tenant data and derived indexes\u002Fcaches are removed according to policy\"]]},\"tunes\":{}},{\"id\":\"p-tests-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"OWASP's authorization regression guidance specifically calls out cross-tenant boundary tests because code changes in caching, queries or shared services can silently break isolation even when role tests continue to pass.\"},\"tunes\":{}},{\"id\":\"h-failures\",\"type\":\"header\",\"data\":{\"text\":\"Common failure modes\",\"level\":2},\"tunes\":{}},{\"id\":\"failures-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Failure mode\",\"Why it fails\"],[\"Check role but not tenant\",\"Valid role becomes cross-tenant authority\"],[\"Trust tenant ID from request\",\"Client controls the isolation selector\"],[\"Scope UI but not API\",\"Hidden buttons do not protect backend resources\"],[\"Tenant-aware detail endpoint, unscoped list endpoint\",\"Bulk reads leak other tenants\"],[\"Tenant filter in most queries\",\"One forgotten path breaks the boundary\"],[\"Global cache keys\",\"Correct database isolation is bypassed by cached data\"],[\"Shared vector index without enforced metadata filters\",\"RAG retrieves another tenant's chunks\"],[\"Queue message tenant ID treated as authorization\",\"Forged or wrongly produced job can cross tenant boundary\"],[\"Platform admin modeled as ordinary ADMIN\",\"Cross-tenant power becomes implicit and difficult to audit\"],[\"Role copied globally across tenant memberships\",\"User receives permissions in tenants where they were never assigned\"],[\"Separate databases but shared privileged credential\",\"Application can still cross databases if its credential is too broad\"],[\"RLS with BYPASSRLS request role\",\"Database policy exists but does not protect the actual request path\"],[\"Random UUIDs treated as isolation\",\"Hard-to-guess identifiers reduce enumeration but do not authorize access\"]]},\"tunes\":{}},{\"id\":\"h-misconceptions\",\"type\":\"header\",\"data\":{\"text\":\"Common misconceptions\",\"level\":2},\"tunes\":{}},{\"id\":\"misconceptions-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Misconception\",\"Correction\"],[\"“RBAC provides tenant isolation.”\",\"RBAC controls permissions; isolation also requires tenant\u002Fresource scoping.\"],[\"“If the user is an admin, tenant checks are unnecessary.”\",\"Admin authority must still have an explicit scope.\"],[\"“Tenant ID in JWT is enough.”\",\"It can be a trusted input only if validated and applied consistently to every protected resource path.\"],[\"“Separate databases remove authorization requirements.”\",\"Users still need operation-level permissions inside their tenant.\"],[\"“A tenant_id column means the system is isolated.”\",\"The field only helps if access paths enforce it.\"],[\"“UUIDs prevent cross-tenant access.”\",\"Unpredictable identifiers are defense in depth, not authorization.\"],[\"“RLS means application code needs no security checks.”\",\"Application authorization, correct DB roles and policy coverage still matter.\"],[\"“One shared vector DB is unsafe.”\",\"It can be safe if isolation is enforceable and verified; physical separation is one option, not the only one.\"],[\"“Platform support needs global ADMIN.”\",\"Cross-tenant support should be a distinct, constrained and auditable authority.\"],[\"“Internal services can skip tenant checks.”\",\"Internal paths can still be compromised or misconfigured and must preserve tenant context.\"]]},\"tunes\":{}},{\"id\":\"h-design\",\"type\":\"header\",\"data\":{\"text\":\"A practical design sequence\",\"level\":2},\"tunes\":{}},{\"id\":\"design-flow\",\"type\":\"processFlow\",\"data\":{\"title\":\"Design permissions and isolation as separate dimensions\",\"orientation\":\"auto\",\"steps\":[{\"label\":\"1. Define tenant ownership\",\"description\":\"Classify which entities and resources are global, tenant-scoped, user-scoped or intentionally cross-tenant.\"},{\"label\":\"2. Define operations\",\"description\":\"Create explicit permissions for reads, writes, publishing, approvals, administration and other business actions.\"},{\"label\":\"3. Define roles\",\"description\":\"Group permissions according to responsibilities without embedding accidental global scope.\"},{\"label\":\"4. Define membership scope\",\"description\":\"Bind role assignments to the tenant\u002Fworkspace\u002Fproject context in which they apply.\"},{\"label\":\"5. Resolve trusted tenant context\",\"description\":\"Derive tenant identity from authenticated, server-verified membership or service authorization.\"},{\"label\":\"6. Enforce resource ownership\",\"description\":\"Apply tenant scope at every tenant-owned data\u002Fservice boundary.\"},{\"label\":\"7. Add defense in depth\",\"description\":\"Use RLS, separate credentials, schemas\u002Fdatabases, storage policies or policy engines where risk justifies them.\"},{\"label\":\"8. Carry scope through derived systems\",\"description\":\"Preserve tenant metadata in cache, search, vector indexes, queues, files and analytics.\"},{\"label\":\"9. Model cross-tenant operations explicitly\",\"description\":\"Separate platform administration and service identities from ordinary tenant roles.\"},{\"label\":\"10. Test both axes\",\"description\":\"Run negative tests for missing permission and for wrong tenant independently.\"},{\"label\":\"11. Audit tenant + permission together\",\"description\":\"Log who acted, in which tenant, on what target and under which authority.\"},{\"label\":\"12. Re-test after schema\u002Fruntime changes\",\"description\":\"Isolation can break when new tables, caches, queues or retrieval paths are introduced.\"}]},\"tunes\":{}},{\"id\":\"h-checklist\",\"type\":\"header\",\"data\":{\"text\":\"RBAC + tenant isolation checklist\",\"level\":2},\"tunes\":{}},{\"id\":\"checklist-table\",\"type\":\"table\",\"data\":{\"withHeadings\":true,\"stretched\":false,\"content\":[[\"Question\",\"Expected answer\"],[\"Who is the principal?\",\"Authenticated user\u002Fservice\u002Fagent identity\"],[\"Which tenant context applies?\",\"Server-verified membership or service scope\"],[\"Which operation is requested?\",\"Typed permission or policy action\"],[\"Does the principal have that permission?\",\"Role\u002Fpolicy decision\"],[\"Who owns the target resource?\",\"Explicit tenant\u002Fglobal\u002Fuser classification\"],[\"Does resource scope match authority?\",\"Tenant-aware lookup\u002Fpolicy\"],[\"Can storage bypass application checks?\",\"Defense-in-depth decision documented\"],[\"Are caches tenant-safe?\",\"Keys\u002Fnamespaces and authorization preserve tenant scope\"],[\"Are files\u002Fblobs tenant-safe?\",\"Object policy and signed URL issuance enforce scope\"],[\"Are async jobs tenant-safe?\",\"Verified context propagates and is revalidated\"],[\"Is RAG\u002Fsearch tenant-safe?\",\"Metadata\u002Fcollection isolation enforced before model context\"],[\"Are cross-tenant admins explicit?\",\"Separate authority, controls and audit\"],[\"Can ordinary credentials bypass isolation?\",\"No, or tightly documented exceptional path\"],[\"Are negative cross-tenant tests automated?\",\"Yes for every relevant access layer\"]]},\"tunes\":{}},{\"id\":\"h-edge\",\"type\":\"header\",\"data\":{\"text\":\"Edge cases and limitations\",\"level\":2},\"tunes\":{}},{\"id\":\"p-edge-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"A user can belong to multiple tenants. The current tenant should therefore be an explicit execution context, not inferred permanently from the user account.\"},\"tunes\":{}},{\"id\":\"p-edge-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Some resources are intentionally shared between selected tenants, such as collaboration spaces or consortium data. This requires an explicit sharing model; pretending the resource belongs to one tenant and adding exceptions later usually creates ambiguous authorization.\"},\"tunes\":{}},{\"id\":\"p-edge-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Noisy-neighbor isolation is related but different from confidentiality isolation. A tenant may never see another tenant's data yet still exhaust shared CPU, queue capacity or database connections. Rate limits and resource quotas can therefore be tenant-aware as an availability boundary.\"},\"tunes\":{}},{\"id\":\"p-edge-4\",\"type\":\"paragraph\",\"data\":{\"text\":\"Physical isolation is not automatically secure if control-plane credentials or administrative paths can cross boundaries. Logical isolation is not automatically weak if policies are centrally enforced, least-privileged and thoroughly tested.\"},\"tunes\":{}},{\"id\":\"p-edge-5\",\"type\":\"paragraph\",\"data\":{\"text\":\"Tenant isolation requirements can differ by data class. Public catalog data, billing records and private AI documents may justify different storage and encryption boundaries inside the same SaaS product.\"},\"tunes\":{}},{\"id\":\"h-change\",\"type\":\"header\",\"data\":{\"text\":\"What would change this answer?\",\"level\":2},\"tunes\":{}},{\"id\":\"p-change-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"The exact implementation changes with architecture: serverless APIs, Kubernetes, PostgreSQL, object storage, vector databases and policy engines expose different isolation primitives.\"},\"tunes\":{}},{\"id\":\"p-change-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"The required strength also changes with regulation, customer contracts, data sensitivity, threat model and operational scale. Some tenants may justify siloed databases or infrastructure while others share pooled resources.\"},\"tunes\":{}},{\"id\":\"p-change-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"The conceptual distinction does not change: permission to perform an operation is not the same thing as permission to cross a tenant boundary.\"},\"tunes\":{}},{\"id\":\"h-related\",\"type\":\"header\",\"data\":{\"text\":\"Related canonical knowledge\",\"level\":2},\"tunes\":{}},{\"id\":\"p-related-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"S01 is a security-boundary prerequisite for Enterprise AI Architecture and AI Governance. Once AI tools, RAG or agents operate over multi-tenant data, tenant identity must travel through retrieval, tool execution, memory, caches and audit traces.\"},\"tunes\":{}},{\"id\":\"p-related-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"It also connects directly to Agentic AI: tool capability and role permission must still be constrained by tenant ownership before an agent can read or mutate business resources.\"},\"tunes\":{}},{\"id\":\"ref-agentic\",\"type\":\"referralArticle\",\"data\":{\"url\":\"https:\u002F\u002Fstajic.de\u002Fde\u002Fblog\u002Fmcp-vs-a2a-vs-ucp-vs-ap2-vs-a2ui-the-agent-protocol-stack-explained\",\"title\":\"MCP vs A2A vs UCP vs AP2 vs A2UI: The Agent Protocol Stack Explained\",\"excerpt\":\"Protocol interoperability does not replace authorization or tenant isolation. Capability discovery and business authority remain separate architecture concerns.\",\"ctaLabel\":\"Read the protocol stack article\"},\"tunes\":{}},{\"id\":\"p-related-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"For RAG, tenant isolation must be enforced before protected chunks reach model context.\"},\"tunes\":{}},{\"id\":\"ref-rag\",\"type\":\"referralArticle\",\"data\":{\"url\":\"https:\u002F\u002Fstajic.de\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works\",\"title\":\"What Is RAG? The Simplest Explanation of How It Works\",\"excerpt\":\"The retrieval foundation for understanding where tenant-aware source filtering and vector-store isolation must be enforced.\",\"ctaLabel\":\"Read the RAG foundation\"},\"tunes\":{}},{\"id\":\"h-faq\",\"type\":\"header\",\"data\":{\"text\":\"Frequently asked questions\",\"level\":2},\"tunes\":{}},{\"id\":\"faq\",\"type\":\"faq\",\"data\":{\"title\":\"RBAC vs tenant isolation FAQ\",\"items\":[{\"id\":\"faq1\",\"question\":\"What is the difference between RBAC and tenant isolation?\",\"answer\":\"RBAC determines which operations a principal may perform. Tenant isolation determines which tenant's resources those operations may access. Secure multi-tenant applications normally need both.\"},{\"id\":\"faq2\",\"question\":\"Does an ADMIN role automatically allow access to all tenants?\",\"answer\":\"No. ADMIN should have an explicit scope. A tenant administrator normally has broad permissions only inside that tenant, while cross-tenant platform administration should be modeled separately.\"},{\"id\":\"faq3\",\"question\":\"Is authentication enough for tenant isolation?\",\"answer\":\"No. Authentication proves identity. Authorization controls permitted actions. Tenant isolation additionally prevents those actions from reaching the wrong tenant's resources.\"},{\"id\":\"faq4\",\"question\":\"Should tenantId be stored in the JWT?\",\"answer\":\"It can be one input to tenant context, but the server must verify current membership\u002Fauthority and enforce the scope at protected resource boundaries. A claim alone does not replace isolation controls.\"},{\"id\":\"faq5\",\"question\":\"Do I need a separate database per tenant?\",\"answer\":\"Not necessarily. Shared-table, RLS, schema, database, infrastructure and hybrid isolation models can all be valid depending on risk and operational requirements.\"},{\"id\":\"faq6\",\"question\":\"Can PostgreSQL RLS replace tenant filters in application code?\",\"answer\":\"RLS can provide strong defense in depth, but correct database roles, request context, policy coverage and application-level authorization still matter.\"},{\"id\":\"faq7\",\"question\":\"How should RAG enforce tenant isolation?\",\"answer\":\"Tenant\u002Faccess scope should be enforced during retrieval so unauthorized chunks never enter model context. Preserve access metadata through chunking and indexing.\"},{\"id\":\"faq8\",\"question\":\"Can one user have different roles in different tenants?\",\"answer\":\"Yes. This is common in B2B SaaS and is a strong reason to scope role assignments by tenant membership rather than treating roles as globally attached to the user.\"},{\"id\":\"faq9\",\"question\":\"What is the best test for tenant isolation?\",\"answer\":\"Use negative cross-tenant tests: create at least two tenants, give a user valid permissions in one tenant, then prove every protected path denies access to the other tenant's resources.\"}]},\"tunes\":{}},{\"id\":\"h-glossary\",\"type\":\"header\",\"data\":{\"text\":\"Glossary\",\"level\":2},\"tunes\":{}},{\"id\":\"glossary\",\"type\":\"glossary\",\"data\":{\"title\":\"Key multi-tenant security terms\",\"entries\":[{\"term\":\"RBAC\",\"definition\":\"Role-Based Access Control: an authorization model that associates permissions with roles and assigns users or principals to those roles.\",\"anchor\":\"rbac\"},{\"term\":\"Tenant\",\"definition\":\"A customer, organization, workspace or other isolated logical consumer of a shared multi-tenant system.\",\"anchor\":\"tenant\"},{\"term\":\"Tenant isolation\",\"definition\":\"Mechanisms that prevent one tenant from accessing, modifying or receiving another tenant's resources in a shared system.\",\"anchor\":\"tenant-isolation\"},{\"term\":\"Authentication\",\"definition\":\"Verification of the identity of a user, service or other principal.\",\"anchor\":\"authentication\"},{\"term\":\"Authorization\",\"definition\":\"Decision process that determines whether a principal may perform a requested operation on a resource.\",\"anchor\":\"authorization\"},{\"term\":\"Permission\",\"definition\":\"A defined allowed operation or capability such as orders.read or users.write.\",\"anchor\":\"permission\"},{\"term\":\"Role\",\"definition\":\"A named grouping of permissions associated with a responsibility or function.\",\"anchor\":\"role\"},{\"term\":\"ABAC\",\"definition\":\"Attribute-Based Access Control: authorization based on attributes of the principal, resource, action or environment.\",\"anchor\":\"abac\"},{\"term\":\"Row-Level Security\",\"definition\":\"Database policy mechanism that restricts which rows a database role or session may read or modify.\",\"anchor\":\"row-level-security\"},{\"term\":\"Cross-tenant access\",\"definition\":\"Any access path in which a principal operating under one tenant context reaches resources belonging to another tenant.\",\"anchor\":\"cross-tenant-access\"},{\"term\":\"Platform administrator\",\"definition\":\"A privileged operational identity with explicitly modeled authority that may span multiple tenants.\",\"anchor\":\"platform-administrator\"},{\"term\":\"Tenant context\",\"definition\":\"The verified tenant scope under which the current request, job or agent operation executes.\",\"anchor\":\"tenant-context\"}]},\"tunes\":{}},{\"id\":\"h-conclusion\",\"type\":\"header\",\"data\":{\"text\":\"Conclusion\",\"level\":2},\"tunes\":{}},{\"id\":\"p-conclusion-1\",\"type\":\"paragraph\",\"data\":{\"text\":\"RBAC and tenant isolation are complementary, not competing security mechanisms. RBAC structures operational permission; tenant isolation constrains the resource boundary inside which that permission can apply.\"},\"tunes\":{}},{\"id\":\"p-conclusion-2\",\"type\":\"paragraph\",\"data\":{\"text\":\"A robust multi-tenant request therefore needs more than “user has role ADMIN.” It needs a verified principal, verified tenant context, an allowed operation, a tenant-scoped target and enforcement at every resource layer that can carry tenant-owned data.\"},\"tunes\":{}},{\"id\":\"p-conclusion-3\",\"type\":\"paragraph\",\"data\":{\"text\":\"The shortest reliable rule is: authorize the action, then isolate the scope — and never assume one proves the other.\"},\"tunes\":{}},{\"id\":\"h-sources\",\"type\":\"header\",\"data\":{\"text\":\"Primary sources and current guidance\",\"level\":2},\"tunes\":{}},{\"id\":\"p-sources-note\",\"type\":\"paragraph\",\"data\":{\"text\":\"The sources below support the RBAC definition and current tenant-isolation guidance. The Aaasaasa AI CMS section is original implementation evidence and is intentionally bounded to the code patterns that were verified.\"},\"tunes\":{}},{\"id\":\"src-nist-rbac\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fcsrc.nist.gov\u002Fprojects\u002Frole-based-access-control\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"NIST — Role Based Access Control\",\"description\":\"NIST overview of RBAC models and the INCITS RBAC standard, including users, roles, permissions, operations and objects.\"}},\"tunes\":{}},{\"id\":\"src-nist-glossary\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fcsrc.nist.gov\u002Fglossary\u002Fterm\u002Frole_based_access_control\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"NIST CSRC — RBAC glossary\",\"description\":\"Current NIST glossary definitions of role-based access control as permission assignment through roles.\"}},\"tunes\":{}},{\"id\":\"src-aws-isolation\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fwhitepapers\u002Flatest\u002Fsaas-tenant-isolation-strategies\u002Fthe-isolation-mindset.html\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"AWS — The isolation mindset\",\"description\":\"AWS SaaS guidance explicitly distinguishing authentication\u002Fauthorization from tenant isolation and recommending shared isolation mechanisms.\"}},\"tunes\":{}},{\"id\":\"src-aws-faq\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fprescriptive-guidance\u002Flatest\u002Fsaas-multitenant-api-access-authorization\u002Ffaq.html\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"AWS — Multi-tenant authorization FAQ\",\"description\":\"Current guidance explaining the difference between authorization and tenant isolation in SaaS applications.\"}},\"tunes\":{}},{\"id\":\"src-aws-avp\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fprescriptive-guidance\u002Flatest\u002Fsaas-multitenant-api-access-authorization\u002Favp-design-considerations.html\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"AWS — Multi-tenant design considerations\",\"description\":\"Current SaaS guidance distinguishing tenant isolation from authorization and discussing pooled\u002Fsiloed authorization policy models.\"}},\"tunes\":{}},{\"id\":\"src-owasp-multi\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FMulti_Tenant_Security_Cheat_Sheet.html\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"OWASP — Multi-Tenant Application Security Cheat Sheet\",\"description\":\"Current practical guidance for tenant context, database isolation, caches, storage, queues, testing and cross-tenant access prevention.\"}},\"tunes\":{}},{\"id\":\"src-owasp-rag\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FRAG_Security_Cheat_Sheet.html\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"OWASP — RAG Security Cheat Sheet\",\"description\":\"Current guidance requiring access control at retrieval time and tenant isolation for multi-tenant vector stores.\"}},\"tunes\":{}},{\"id\":\"src-owasp-auth-test\",\"type\":\"linkTool\",\"data\":{\"link\":\"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FAuthorization_Regression_Testing_Cheat_Sheet.html\",\"meta\":{\"image\":{\"url\":\"\"},\"title\":\"OWASP — Authorization Regression Testing\",\"description\":\"Current testing guidance including role-demotion and cross-tenant boundary tests.\"}},\"tunes\":{}}],\"version\":\"2.31.6\"}",{"time":1451,"blocks":1452,"version":2441},1791485112883,[1453,1457,1462,1467,1472,1476,1480,1484,1488,1492,1496,1500,1504,1508,1512,1516,1520,1524,1547,1551,1555,1559,1563,1567,1594,1598,1617,1621,1625,1629,1633,1637,1641,1645,1649,1653,1657,1661,1671,1675,1679,1683,1687,1692,1696,1728,1732,1736,1740,1744,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1817,1821,1825,1829,1833,1837,1841,1845,1849,1853,1857,1861,1865,1869,1873,1877,1881,1907,1911,1916,1920,1924,1928,1932,1936,1961,1966,1970,1974,1978,1982,1986,2023,2027,2031,2077,2081,2118,2122,2163,2167,2215,2219,2223,2227,2231,2235,2239,2243,2247,2251,2255,2259,2263,2267,2273,2277,2284,2288,2320,2324,2361,2365,2369,2373,2377,2381,2385,2392,2399,2406,2413,2420,2427,2434],{"id":215,"data":1454,"type":218,"tunes":1456},{"text":1455},"RBAC and tenant isolation solve two different security problems in multi-tenant systems. Role-Based Access Control (RBAC) determines what an authenticated principal is allowed to do, such as read orders, edit products or manage users. Tenant isolation determines which tenant's data, resources and execution context that principal is allowed to access. A user can be correctly authenticated and correctly assigned an RBAC role yet still experience a security failure if the application lets that role operate on another tenant's resources.",{},{"id":221,"data":1458,"type":226,"tunes":1461},{"body":1459,"title":1460,"variant":225},"\u003Cstrong>RBAC answers “what may this identity do?” Tenant isolation answers “inside whose boundary may it do it?”\u003C\u002Fstrong>\u003Cbr>\u003Cbr>A secure multi-tenant application normally needs both. A tenant administrator may have broad permissions, but those permissions should remain constrained to the administrator's tenant unless an explicitly separate platform-level authority exists.","Direct answer",{},{"id":229,"data":1463,"type":226,"tunes":1466},{"body":1464,"title":1465,"variant":233},"Giving a user the role \u003Ccode>ADMIN\u003C\u002Fcode> does not automatically imply “administrator of tenant A only.” The role must be evaluated together with verified tenant context and the target resource's tenant ownership. Otherwise a valid role can become a cross-tenant privilege.","A role is not a tenant boundary",{},{"id":236,"data":1468,"type":226,"tunes":1471},{"body":1469,"title":1470,"variant":240},"The underlying distinction is stable. NIST defines RBAC around users, roles, permissions, operations and objects. Current AWS SaaS guidance explicitly states that authentication and authorization are not equal to tenant isolation, and that a user can be authenticated and authorized while still accessing another tenant's resources if isolation is not separately enforced. OWASP's current Multi-Tenant Security guidance likewise treats tenant isolation as a cross-layer requirement covering APIs, databases, caches, storage, queues and other shared resources.","Current-source note — 8 October 2026",{},{"id":243,"data":1473,"type":248,"tunes":1475},{"title":1474,"maxLevel":246,"minLevel":247},"Contents",{},{"id":251,"data":1477,"type":42,"tunes":1479},{"text":1478,"level":247},"What RBAC really controls",{},{"id":256,"data":1481,"type":218,"tunes":1483},{"text":1482},"RBAC is an authorization model in which permissions are associated with roles and users are assigned to those roles. The role acts as an administrative abstraction between identities and permissions.",{},{"id":261,"data":1485,"type":218,"tunes":1487},{"text":1486},"NIST's classic RBAC work formalizes this around users, roles, permissions, operations and objects. The practical benefit is that an organization can manage authorization through relatively stable job or responsibility roles rather than attaching every permission directly to every user.",{},{"id":266,"data":1489,"type":218,"tunes":1491},{"text":1490},"A role such as EDITOR can therefore mean: may read content, write content and publish content. A role such as ACCOUNTANT may mean: may read billing data, reconcile invoices and approve settlements.",{},{"id":271,"data":1493,"type":42,"tunes":1495},{"text":1494,"level":247},"What tenant isolation really controls",{},{"id":276,"data":1497,"type":218,"tunes":1499},{"text":1498},"Tenant isolation is the set of mechanisms that prevents one tenant from reading, modifying, influencing or accidentally receiving another tenant's resources in a shared system.",{},{"id":281,"data":1501,"type":218,"tunes":1503},{"text":1502},"The protected boundary is broader than database rows. Tenant-specific state can exist in relational tables, object storage, vector indexes, caches, search indexes, queue messages, files, temporary artifacts, background jobs, analytics, rate limits and infrastructure resources.",{},{"id":286,"data":1505,"type":218,"tunes":1507},{"text":1506},"AWS's SaaS guidance makes the distinction explicit: authorization grants access to resources, while tenant isolation ensures those resources cannot cross the wrong tenant boundary even when infrastructure is shared.",{},{"id":291,"data":1509,"type":42,"tunes":1511},{"text":1510,"level":247},"The simplest example",{},{"id":296,"data":1513,"type":218,"tunes":1515},{"text":1514},"Suppose Alice is an administrator for Tenant A and Bob is an administrator for Tenant B. Both users legitimately hold the same ADMIN role.",{},{"id":301,"data":1517,"type":218,"tunes":1519},{"text":1518},"RBAC can correctly conclude that both users may execute an operation such as users.read. But when Alice requests user ID 847, the application must still verify that user 847 belongs to Tenant A.",{},{"id":306,"data":1521,"type":218,"tunes":1523},{"text":1522},"If the API checks only “Alice has ADMIN” and then executes SELECT * FROM users WHERE id = 847, RBAC succeeded while tenant isolation failed.",{},{"id":311,"data":1525,"type":334,"tunes":1546},{"steps":1526,"title":1545,"orientation":333},[1527,1530,1533,1536,1539,1542],{"label":1528,"description":1529},"1. Authenticate principal","Establish who the user, service or agent is.",{"label":1531,"description":1532},"2. Resolve verified tenant context","Determine which tenant context applies from trusted server-side identity\u002Fmembership information.",{"label":1534,"description":1535},"3. Resolve permission","Evaluate whether the principal's role or policy permits the requested operation.",{"label":1537,"description":1538},"4. Scope the target resource","Verify that the target object belongs to the permitted tenant or explicitly shared scope.",{"label":1540,"description":1541},"5. Enforce at the access boundary","Perform the database, cache, storage, queue or service operation with tenant constraints applied.",{"label":1543,"description":1544},"6. Audit both dimensions","Record principal, tenant, operation, target and result so cross-tenant attempts are visible.","A correct multi-tenant authorization decision",{},{"id":337,"data":1548,"type":42,"tunes":1550},{"text":1549,"level":247},"Where the simple example stops",{},{"id":342,"data":1552,"type":218,"tunes":1554},{"text":1553},"Real systems often contain several classes of identity: tenant users, platform administrators, background workers, integrations, agents and cross-tenant operational services. Some of these legitimately cross tenant boundaries.",{},{"id":347,"data":1556,"type":218,"tunes":1558},{"text":1557},"That does not remove the need for isolation. It means cross-tenant authority must be explicit, narrow and separately auditable rather than emerging accidentally from a global role or unscoped database connection.",{},{"id":352,"data":1560,"type":218,"tunes":1562},{"text":1561},"Tenant isolation can also vary by layer. A product may share application servers while separating databases, or use a shared database with row-level policies while giving premium tenants isolated storage or compute. There is no single universal isolation topology.",{},{"id":357,"data":1564,"type":42,"tunes":1566},{"text":1565,"level":247},"RBAC vs tenant isolation",{},{"id":362,"data":1568,"type":399,"tunes":1593},{"rows":1569,"title":1588,"layout":391,"columns":1589},[1570,1573,1576,1579,1582,1585],{"id":366,"label":1571,"values":1572},"Primary question",[369,369],{"id":371,"label":1574,"values":1575},"Typical unit",[369,369],{"id":375,"label":1577,"values":1578},"Example",[369,369],{"id":379,"label":1580,"values":1581},"Typical failure",[369,369],{"id":383,"label":1583,"values":1584},"Typical implementation",[369,369],{"id":387,"label":1586,"values":1587},"Can it exist alone?",[369,369],"Two different security dimensions",[1590,1591],{"id":394,"label":395},{"id":397,"label":1592},"Tenant isolation",{},{"id":402,"data":1595,"type":42,"tunes":1597},{"text":1596,"level":247},"Authentication, authorization and isolation are three different checks",{},{"id":407,"data":1599,"type":391,"tunes":1616},{"content":1600,"stretched":43,"withHeadings":14},[1601,1605,1609,1613],[1602,1603,1604],"Layer","Question","Example failure",[1606,1607,1608],"Authentication","Who is this principal?","Attacker impersonates Alice",[1610,1611,1612],"Authorization \u002F RBAC","May this principal perform this operation?","Viewer can delete users",[1592,1614,1615],"May this operation reach this tenant\u002Fresource boundary?","Tenant A admin reads Tenant B order",{},{"id":427,"data":1618,"type":218,"tunes":1620},{"text":1619},"These checks are related but non-substitutable. Authentication can be perfect while authorization fails. Authorization can be correct while tenant isolation fails. A secure SaaS request path needs all applicable boundaries.",{},{"id":432,"data":1622,"type":42,"tunes":1624},{"text":1623,"level":247},"Roles need a scope",{},{"id":437,"data":1626,"type":218,"tunes":1628},{"text":1627},"The word ADMIN is incomplete without scope. It can mean platform administrator, tenant administrator, project administrator, workspace administrator or administrator of one subsystem.",{},{"id":442,"data":1630,"type":218,"tunes":1632},{"text":1631},"In multi-tenant systems, role assignment should normally be associated with tenant membership or another explicit resource scope. The same user may legitimately be ADMIN in Tenant A and VIEWER in Tenant B.",{},{"id":447,"data":1634,"type":218,"tunes":1636},{"text":1635},"A global role model that ignores this distinction can create privilege leakage even when the permission map itself is correct.",{},{"id":452,"data":1638,"type":42,"tunes":1640},{"text":1639,"level":247},"Tenant context must come from a trusted path",{},{"id":457,"data":1642,"type":218,"tunes":1644},{"text":1643},"A tenant ID supplied by the client is useful as a selector, but it is not proof of authority. The server must derive or verify tenant membership against authenticated identity and current authorization data.",{},{"id":462,"data":1646,"type":218,"tunes":1648},{"text":1647},"OWASP's current multi-tenant guidance recommends establishing tenant context early in the request lifecycle and explicitly warns against treating client headers or request parameters as authorization proof.",{},{"id":467,"data":1650,"type":218,"tunes":1652},{"text":1651},"This matters because a trivial request modification from tenant=A to tenant=B must not be sufficient to cross the isolation boundary.",{},{"id":472,"data":1654,"type":42,"tunes":1656},{"text":1655,"level":247},"Tenant scope belongs in the resource lookup",{},{"id":477,"data":1658,"type":218,"tunes":1660},{"text":1659},"A common application-level isolation pattern is to include tenant scope in the same query that resolves the resource.",{},{"id":482,"data":1662,"type":391,"tunes":1670},{"content":1663,"stretched":43,"withHeadings":14},[1664,1667,1668,1669],[1665,1666],"Weak lookup","Stronger tenant-scoped lookup",[489,490],[492,493],[495,496],{},{"id":499,"data":1672,"type":218,"tunes":1674},{"text":1673},"This pattern is not the only possible isolation mechanism, but it keeps tenant ownership close to the data access operation and prevents an object ID from becoming a cross-tenant capability.",{},{"id":504,"data":1676,"type":42,"tunes":1678},{"text":1677,"level":247},"Application checks are useful, but isolation should not depend on perfect developer behavior",{},{"id":509,"data":1680,"type":218,"tunes":1682},{"text":1681},"AWS's isolation guidance explicitly warns against leaving isolation enforcement only to service developers. In a large codebase, eventually one query, cache key or worker path may omit tenant scope.",{},{"id":514,"data":1684,"type":218,"tunes":1686},{"text":1685},"Defense in depth can therefore move isolation into shared middleware, repository\u002Fservice layers, policy engines, database Row-Level Security, dedicated credentials, separate schemas or separate databases depending on risk and architecture.",{},{"id":519,"data":1688,"type":226,"tunes":1691},{"body":1689,"title":1690,"variant":523},"The strongest boundary is one that ordinary application code cannot casually bypass by omitting one \u003Ccode>tenantId\u003C\u002Fcode> condition.","Isolation should be hard to forget",{},{"id":526,"data":1693,"type":42,"tunes":1695},{"text":1694,"level":247},"Database isolation strategies",{},{"id":531,"data":1697,"type":391,"tunes":1727},{"content":1698,"stretched":43,"withHeadings":14},[1699,1703,1707,1711,1715,1719,1723],[1700,1701,1702],"Strategy","Boundary","Strength \u002F trade-off",[1704,1705,1706],"Shared tables + tenant key","Row\u002Fapplication policy","Operationally efficient; requires exhaustive tenant scoping and strong tests",[1708,1709,1710],"Shared tables + database RLS","Database policy boundary","Reduces dependence on every application query; requires correct roles, session\u002Ftransaction tenant context and policy coverage",[1712,1713,1714],"Separate schemas","Namespace \u002F DB-role boundary","Stronger logical separation; more operational complexity",[1716,1717,1718],"Separate databases","Database \u002F credential boundary","Strong isolation and simpler blast-radius story; higher provisioning and operations cost",[1720,1721,1722],"Separate infrastructure\u002Faccount","Infrastructure boundary","Strongest coarse-grained separation; highest cost and operational overhead",[1724,1725,1726],"Hybrid","Per workload\u002Fdata class","Allows stronger isolation only where risk\u002Fcompliance justifies it",{},{"id":564,"data":1729,"type":218,"tunes":1731},{"text":1730},"OWASP's current Multi-Tenant Security Cheat Sheet lists separate databases, separate schemas, shared tables with row-level controls and hybrid models. The correct model depends on threat level, compliance, performance and operational cost.",{},{"id":569,"data":1733,"type":42,"tunes":1735},{"text":1734,"level":247},"PostgreSQL Row-Level Security can provide defense in depth",{},{"id":574,"data":1737,"type":218,"tunes":1739},{"text":1738},"With shared tables, PostgreSQL Row-Level Security can enforce a tenant predicate at the database layer so ordinary queries cannot see rows outside the active tenant policy.",{},{"id":579,"data":1741,"type":218,"tunes":1743},{"text":1742},"However, RLS is not magic. PostgreSQL superusers and roles with BYPASSRLS can bypass row policies. OWASP therefore recommends using a least-privileged request-path role and testing the same connection\u002Fpooling mode used in production.",{},{"id":584,"data":1745,"type":218,"tunes":1747},{"text":1746},"Connection reuse is another important edge: tenant context must be set and reset safely for every transaction\u002Frequest so one pooled connection cannot leak prior tenant state.",{},{"id":589,"data":1749,"type":42,"tunes":1751},{"text":1750,"level":247},"Tenant isolation must include caches",{},{"id":594,"data":1753,"type":218,"tunes":1755},{"text":1754},"A database query can be perfectly scoped and still leak data through a shared cache key.",{},{"id":599,"data":1757,"type":218,"tunes":1759},{"text":1758},"If user:42 exists in both Tenant A and Tenant B, a global cache key can return the wrong tenant's value. Tenant-sensitive cache keys should include every attribute that changes visibility or result semantics, commonly tenant, user, locale, feature set or permission version.",{},{"id":604,"data":1761,"type":218,"tunes":1763},{"text":1762},"Cache partitioning is defense in depth, not a replacement for authorization. The request still needs to be authorized before protected cached content is returned.",{},{"id":609,"data":1765,"type":42,"tunes":1767},{"text":1766,"level":247},"Files and object storage need their own tenant boundary",{},{"id":614,"data":1769,"type":218,"tunes":1771},{"text":1770},"Object storage should distinguish global, tenant-scoped and user-scoped objects. A folder prefix alone is only a naming convention unless access policy actually constrains reads and writes.",{},{"id":619,"data":1773,"type":218,"tunes":1775},{"text":1774},"Stronger designs may use tenant-aware object keys, bucket policies, separate buckets\u002Faccounts or tenant-specific encryption keys where risk or compliance requires stronger isolation.",{},{"id":624,"data":1777,"type":218,"tunes":1779},{"text":1778},"Signed URLs must be authorized before issuance and scoped to the exact object and operation. Possession of an object identifier should not itself grant cross-tenant access.",{},{"id":629,"data":1781,"type":42,"tunes":1783},{"text":1782,"level":247},"Background jobs and queues can break isolation",{},{"id":634,"data":1785,"type":218,"tunes":1787},{"text":1786},"Async jobs often leave the original HTTP request context, which makes tenant propagation easy to mishandle. A queue message containing tenantId is not sufficient proof that the producer was authorized.",{},{"id":639,"data":1789,"type":218,"tunes":1791},{"text":1790},"The worker should carry a verified service\u002Fuser identity or trusted job envelope, re-establish tenant context and re-authorize consequential operations at the consumer boundary.",{},{"id":644,"data":1793,"type":218,"tunes":1795},{"text":1794},"Tenant isolation also includes availability. One tenant should not be able to monopolize shared workers, queues, connection pools or compute in ways that materially degrade other tenants.",{},{"id":649,"data":1797,"type":42,"tunes":1799},{"text":1798,"level":247},"Search and RAG need tenant-aware retrieval",{},{"id":654,"data":1801,"type":218,"tunes":1803},{"text":1802},"Multi-tenant AI introduces another copy of the isolation problem. Documents may be chunked, embedded and stored in a vector index after ingestion.",{},{"id":659,"data":1805,"type":218,"tunes":1807},{"text":1806},"OWASP's current RAG security guidance states that access control must be enforced at retrieval time and that chunks from Tenant A must not be retrieved by queries from Tenant B. Document-level permissions cannot simply be assumed to survive chunking automatically.",{},{"id":664,"data":1809,"type":218,"tunes":1811},{"text":1810},"The vector index therefore needs tenant\u002Faccess metadata or physically\u002Flogically separate collections according to the isolation design. Retrieval filters should be applied before unauthorized content can enter model context.",{},{"id":669,"data":1813,"type":226,"tunes":1816},{"body":1814,"title":1815,"variant":233},"Do not retrieve cross-tenant chunks and then instruct the language model to ignore them. Once protected data enters model context, the isolation boundary has already failed.","The model must never be the tenant filter",{},{"id":675,"data":1818,"type":42,"tunes":1820},{"text":1819,"level":247},"Derived data inherits tenant sensitivity",{},{"id":680,"data":1822,"type":218,"tunes":1824},{"text":1823},"Embeddings, search indexes, thumbnails, generated summaries, caches, analytics rows and AI responses are derived from source data. Their tenant scope should follow the source unless an explicit transformation creates a legitimate shared\u002Fglobal artifact.",{},{"id":685,"data":1826,"type":218,"tunes":1828},{"text":1827},"Deletion and offboarding must therefore propagate beyond the canonical row. Removing a tenant document while leaving searchable chunks or cached summaries can retain cross-tenant or post-retention exposure.",{},{"id":690,"data":1830,"type":42,"tunes":1832},{"text":1831,"level":247},"Not everything belongs to a tenant",{},{"id":695,"data":1834,"type":218,"tunes":1836},{"text":1835},"Multi-tenant platforms often have intentionally global resources: product taxonomies, public templates, system permissions, feature definitions or public content.",{},{"id":700,"data":1838,"type":218,"tunes":1840},{"text":1839},"The safest model is explicit classification: global, tenant-scoped, user-scoped or explicitly cross-tenant. Ambiguous resources are where accidental leakage begins.",{},{"id":705,"data":1842,"type":218,"tunes":1844},{"text":1843},"An intentionally shared object should have a documented reason for being global rather than simply lacking a tenant association.",{},{"id":710,"data":1846,"type":42,"tunes":1848},{"text":1847,"level":247},"Platform administrators require a different authority model",{},{"id":715,"data":1850,"type":218,"tunes":1852},{"text":1851},"A platform operator may need to inspect multiple tenants for support, compliance or infrastructure operations. Modeling this as an ordinary tenant ADMIN with accidental global database access weakens both security and auditability.",{},{"id":720,"data":1854,"type":218,"tunes":1856},{"text":1855},"A better design uses a distinct platform identity or explicit cross-tenant permission, stronger authentication, purpose limitation, detailed audit and, where appropriate, approval or break-glass controls.",{},{"id":725,"data":1858,"type":218,"tunes":1860},{"text":1859},"Cross-tenant access should therefore be a named capability, not the absence of a tenant filter.",{},{"id":730,"data":1862,"type":42,"tunes":1864},{"text":1863,"level":247},"RBAC can be combined with attributes",{},{"id":735,"data":1866,"type":218,"tunes":1868},{"text":1867},"Some decisions depend on more than role. Tenant membership, region, resource owner, subscription tier, time, project membership or data classification can all affect access.",{},{"id":740,"data":1870,"type":218,"tunes":1872},{"text":1871},"RBAC and ABAC are not mutually exclusive. AWS's current multi-tenant authorization guidance discusses RBAC, ABAC and hybrid models. A role can define broad responsibility while attributes constrain which concrete resource instance can be accessed.",{},{"id":745,"data":1874,"type":218,"tunes":1876},{"text":1875},"The key architecture rule remains: do not encode tenant isolation only as an incidental role name if tenant identity is a first-class resource boundary.",{},{"id":750,"data":1878,"type":42,"tunes":1880},{"text":1879,"level":247},"Authorization decisions are at least two-dimensional",{},{"id":755,"data":1882,"type":391,"tunes":1906},{"content":1883,"stretched":43,"withHeadings":14},[1884,1889,1892,1895,1897,1898,1902],[1885,1886,1887,1888],"Principal","Role permission","Tenant relationship","Decision",[764,765,1890,1891],"Order belongs to Alice's tenant","Allow",[764,765,1893,1894],"Order belongs to another tenant","Deny",[764,772,1890,1896],"Allow if role includes write",[764,772,1893,1894],[1899,777,1900,1901],"Platform support","Explicit support scope + audited target tenant","Potentially allow under platform policy",[1903,782,1904,1905],"Background worker","Trusted service scope for job tenant","Allow only for verified job tenant",{},{"id":787,"data":1908,"type":42,"tunes":1910},{"text":1909,"level":247},"Original implementation evidence: Aaasaasa AI CMS",{},{"id":792,"data":1912,"type":226,"tunes":1915},{"body":1913,"title":1914,"variant":240},"Aaasaasa AI CMS contains a concrete tenant-scoped RBAC implementation. It is useful evidence for how role authorization and tenant scope can be combined, but it should not be presented as proof that every storage, cache or infrastructure layer has complete tenant isolation.","Original implementation evidence",{},{"id":798,"data":1917,"type":218,"tunes":1919},{"text":1918},"The RBAC service defines typed permission codes such as cms.content.read, shop.orders.write, billing.reconcile and users.roles. System roles map those permissions into named responsibility sets.",{},{"id":803,"data":1921,"type":218,"tunes":1923},{"text":1922},"Role records are created and resolved with a tenantId. System roles are upserted using a composite tenant\u002Fcode identity, and role listing is filtered by tenant.",{},{"id":808,"data":1925,"type":218,"tunes":1927},{"text":1926},"Role update and deletion first resolve the role using both role ID and tenant ID. User-role assignments are also stored and replaced under the current tenant context.",{},{"id":813,"data":1929,"type":218,"tunes":1931},{"text":1930},"Permission resolution reads explicit user-role assignments scoped by both tenantId and userId. This prevents one tenant's role assignment from automatically becoming another tenant's role assignment.",{},{"id":818,"data":1933,"type":218,"tunes":1935},{"text":1934},"At API level, administrative RBAC routes resolve a tenant context before creating or modifying roles. This is the correct direction: permission administration itself must respect tenancy.",{},{"id":823,"data":1937,"type":391,"tunes":1960},{"content":1938,"stretched":43,"withHeadings":14},[1939,1942,1945,1948,1951,1954,1957],[1940,1941],"Observed implementation pattern","Security meaning",[1943,1944],"Typed permission codes","RBAC operation vocabulary is explicit",[1946,1947],"System role → permission maps","Roles aggregate permissions rather than hard-coding users",[1949,1950],"tenantId_code role identity","Same logical role can exist separately per tenant",[1952,1953],"Role lookup uses id + tenantId","Role mutation is tenant-scoped",[1955,1956],"User-role relation stores tenantId","Membership is not globally inferred from role alone",[1958,1959],"Permission resolution uses tenantId + userId","Authorization is evaluated inside tenant context",{},{"id":849,"data":1962,"type":226,"tunes":1965},{"body":1963,"title":1964,"variant":233},"Tenant-scoped RBAC is one layer. Complete tenant isolation must also cover all tenant-owned resource lookups, databases, caches, files, search\u002Fvector indexes, background jobs, integrations and operational paths. The repository evidence here supports the RBAC\u002Ftenant-scope design pattern, not a claim of independently audited SaaS isolation.","What this evidence does not prove",{},{"id":855,"data":1967,"type":42,"tunes":1969},{"text":1968,"level":247},"Why this distinction matters even more for AI agents",{},{"id":860,"data":1971,"type":218,"tunes":1973},{"text":1972},"AI agents can turn a permission mistake into a sequence of actions. If an agent is given a broad orders.read tool without tenant-scoped enforcement, a reasoning or prompt-injection failure can cause cross-tenant reads at machine speed.",{},{"id":865,"data":1975,"type":218,"tunes":1977},{"text":1976},"Agent tool descriptions can mention tenant constraints, but enforcement must still happen in the trusted runtime\u002Fservice\u002Fdata layer. Natural-language instructions are not an authorization boundary.",{},{"id":870,"data":1979,"type":218,"tunes":1981},{"text":1980},"The same applies to RAG: an agent can have permission to use the search tool while the search backend must still prevent Tenant A's query from returning Tenant B's chunks.",{},{"id":875,"data":1983,"type":42,"tunes":1985},{"text":1984,"level":247},"Test RBAC and tenant isolation separately",{},{"id":880,"data":1987,"type":391,"tunes":2022},{"content":1988,"stretched":43,"withHeadings":14},[1989,1992,1995,1998,2001,2004,2007,2010,2013,2016,2019],[1990,1991],"Test family","What it should prove",[1993,1994],"Role demotion test","A user without a permission cannot perform the operation even inside their own tenant",[1996,1997],"Cross-tenant object test","A user with the correct role still cannot access the same resource type in another tenant",[1999,2000],"Identifier tampering","Changing object\u002Ftenant IDs does not cross scope",[2002,2003],"List\u002Fbulk endpoint test","Broad queries return only authorized tenant data",[2005,2006],"Cache reuse test","Two tenants using reused processes\u002Fconnections never receive each other's cached state",[2008,2009],"RLS request-role test","Production request role cannot bypass row policies",[2011,2012],"Async worker test","Tenant context survives queueing and is revalidated at consumption",[2014,2015],"Vector retrieval test","Tenant A query never retrieves Tenant B chunks",[2017,2018],"Platform-admin test","Cross-tenant capability is explicit, narrow and auditable",[2020,2021],"Offboarding test","Tenant data and derived indexes\u002Fcaches are removed according to policy",{},{"id":918,"data":2024,"type":218,"tunes":2026},{"text":2025},"OWASP's authorization regression guidance specifically calls out cross-tenant boundary tests because code changes in caching, queries or shared services can silently break isolation even when role tests continue to pass.",{},{"id":923,"data":2028,"type":42,"tunes":2030},{"text":2029,"level":247},"Common failure modes",{},{"id":928,"data":2032,"type":391,"tunes":2076},{"content":2033,"stretched":43,"withHeadings":14},[2034,2037,2040,2043,2046,2049,2052,2055,2058,2061,2064,2067,2070,2073],[2035,2036],"Failure mode","Why it fails",[2038,2039],"Check role but not tenant","Valid role becomes cross-tenant authority",[2041,2042],"Trust tenant ID from request","Client controls the isolation selector",[2044,2045],"Scope UI but not API","Hidden buttons do not protect backend resources",[2047,2048],"Tenant-aware detail endpoint, unscoped list endpoint","Bulk reads leak other tenants",[2050,2051],"Tenant filter in most queries","One forgotten path breaks the boundary",[2053,2054],"Global cache keys","Correct database isolation is bypassed by cached data",[2056,2057],"Shared vector index without enforced metadata filters","RAG retrieves another tenant's chunks",[2059,2060],"Queue message tenant ID treated as authorization","Forged or wrongly produced job can cross tenant boundary",[2062,2063],"Platform admin modeled as ordinary ADMIN","Cross-tenant power becomes implicit and difficult to audit",[2065,2066],"Role copied globally across tenant memberships","User receives permissions in tenants where they were never assigned",[2068,2069],"Separate databases but shared privileged credential","Application can still cross databases if its credential is too broad",[2071,2072],"RLS with BYPASSRLS request role","Database policy exists but does not protect the actual request path",[2074,2075],"Random UUIDs treated as isolation","Hard-to-guess identifiers reduce enumeration but do not authorize access",{},{"id":975,"data":2078,"type":42,"tunes":2080},{"text":2079,"level":247},"Common misconceptions",{},{"id":980,"data":2082,"type":391,"tunes":2117},{"content":2083,"stretched":43,"withHeadings":14},[2084,2087,2090,2093,2096,2099,2102,2105,2108,2111,2114],[2085,2086],"Misconception","Correction",[2088,2089],"“RBAC provides tenant isolation.”","RBAC controls permissions; isolation also requires tenant\u002Fresource scoping.",[2091,2092],"“If the user is an admin, tenant checks are unnecessary.”","Admin authority must still have an explicit scope.",[2094,2095],"“Tenant ID in JWT is enough.”","It can be a trusted input only if validated and applied consistently to every protected resource path.",[2097,2098],"“Separate databases remove authorization requirements.”","Users still need operation-level permissions inside their tenant.",[2100,2101],"“A tenant_id column means the system is isolated.”","The field only helps if access paths enforce it.",[2103,2104],"“UUIDs prevent cross-tenant access.”","Unpredictable identifiers are defense in depth, not authorization.",[2106,2107],"“RLS means application code needs no security checks.”","Application authorization, correct DB roles and policy coverage still matter.",[2109,2110],"“One shared vector DB is unsafe.”","It can be safe if isolation is enforceable and verified; physical separation is one option, not the only one.",[2112,2113],"“Platform support needs global ADMIN.”","Cross-tenant support should be a distinct, constrained and auditable authority.",[2115,2116],"“Internal services can skip tenant checks.”","Internal paths can still be compromised or misconfigured and must preserve tenant context.",{},{"id":1018,"data":2119,"type":42,"tunes":2121},{"text":2120,"level":247},"A practical design sequence",{},{"id":1023,"data":2123,"type":334,"tunes":2162},{"steps":2124,"title":2161,"orientation":333},[2125,2128,2131,2134,2137,2140,2143,2146,2149,2152,2155,2158],{"label":2126,"description":2127},"1. Define tenant ownership","Classify which entities and resources are global, tenant-scoped, user-scoped or intentionally cross-tenant.",{"label":2129,"description":2130},"2. Define operations","Create explicit permissions for reads, writes, publishing, approvals, administration and other business actions.",{"label":2132,"description":2133},"3. Define roles","Group permissions according to responsibilities without embedding accidental global scope.",{"label":2135,"description":2136},"4. Define membership scope","Bind role assignments to the tenant\u002Fworkspace\u002Fproject context in which they apply.",{"label":2138,"description":2139},"5. Resolve trusted tenant context","Derive tenant identity from authenticated, server-verified membership or service authorization.",{"label":2141,"description":2142},"6. Enforce resource ownership","Apply tenant scope at every tenant-owned data\u002Fservice boundary.",{"label":2144,"description":2145},"7. Add defense in depth","Use RLS, separate credentials, schemas\u002Fdatabases, storage policies or policy engines where risk justifies them.",{"label":2147,"description":2148},"8. Carry scope through derived systems","Preserve tenant metadata in cache, search, vector indexes, queues, files and analytics.",{"label":2150,"description":2151},"9. Model cross-tenant operations explicitly","Separate platform administration and service identities from ordinary tenant roles.",{"label":2153,"description":2154},"10. Test both axes","Run negative tests for missing permission and for wrong tenant independently.",{"label":2156,"description":2157},"11. Audit tenant + permission together","Log who acted, in which tenant, on what target and under which authority.",{"label":2159,"description":2160},"12. Re-test after schema\u002Fruntime changes","Isolation can break when new tables, caches, queues or retrieval paths are introduced.","Design permissions and isolation as separate dimensions",{},{"id":1065,"data":2164,"type":42,"tunes":2166},{"text":2165,"level":247},"RBAC + tenant isolation checklist",{},{"id":1070,"data":2168,"type":391,"tunes":2214},{"content":2169,"stretched":43,"withHeadings":14},[2170,2172,2175,2178,2181,2184,2187,2190,2193,2196,2199,2202,2205,2208,2211],[1603,2171],"Expected answer",[2173,2174],"Who is the principal?","Authenticated user\u002Fservice\u002Fagent identity",[2176,2177],"Which tenant context applies?","Server-verified membership or service scope",[2179,2180],"Which operation is requested?","Typed permission or policy action",[2182,2183],"Does the principal have that permission?","Role\u002Fpolicy decision",[2185,2186],"Who owns the target resource?","Explicit tenant\u002Fglobal\u002Fuser classification",[2188,2189],"Does resource scope match authority?","Tenant-aware lookup\u002Fpolicy",[2191,2192],"Can storage bypass application checks?","Defense-in-depth decision documented",[2194,2195],"Are caches tenant-safe?","Keys\u002Fnamespaces and authorization preserve tenant scope",[2197,2198],"Are files\u002Fblobs tenant-safe?","Object policy and signed URL issuance enforce scope",[2200,2201],"Are async jobs tenant-safe?","Verified context propagates and is revalidated",[2203,2204],"Is RAG\u002Fsearch tenant-safe?","Metadata\u002Fcollection isolation enforced before model context",[2206,2207],"Are cross-tenant admins explicit?","Separate authority, controls and audit",[2209,2210],"Can ordinary credentials bypass isolation?","No, or tightly documented exceptional path",[2212,2213],"Are negative cross-tenant tests automated?","Yes for every relevant access layer",{},{"id":1119,"data":2216,"type":42,"tunes":2218},{"text":2217,"level":247},"Edge cases and limitations",{},{"id":1124,"data":2220,"type":218,"tunes":2222},{"text":2221},"A user can belong to multiple tenants. The current tenant should therefore be an explicit execution context, not inferred permanently from the user account.",{},{"id":1129,"data":2224,"type":218,"tunes":2226},{"text":2225},"Some resources are intentionally shared between selected tenants, such as collaboration spaces or consortium data. This requires an explicit sharing model; pretending the resource belongs to one tenant and adding exceptions later usually creates ambiguous authorization.",{},{"id":1134,"data":2228,"type":218,"tunes":2230},{"text":2229},"Noisy-neighbor isolation is related but different from confidentiality isolation. A tenant may never see another tenant's data yet still exhaust shared CPU, queue capacity or database connections. Rate limits and resource quotas can therefore be tenant-aware as an availability boundary.",{},{"id":1139,"data":2232,"type":218,"tunes":2234},{"text":2233},"Physical isolation is not automatically secure if control-plane credentials or administrative paths can cross boundaries. Logical isolation is not automatically weak if policies are centrally enforced, least-privileged and thoroughly tested.",{},{"id":1144,"data":2236,"type":218,"tunes":2238},{"text":2237},"Tenant isolation requirements can differ by data class. Public catalog data, billing records and private AI documents may justify different storage and encryption boundaries inside the same SaaS product.",{},{"id":1149,"data":2240,"type":42,"tunes":2242},{"text":2241,"level":247},"What would change this answer?",{},{"id":1154,"data":2244,"type":218,"tunes":2246},{"text":2245},"The exact implementation changes with architecture: serverless APIs, Kubernetes, PostgreSQL, object storage, vector databases and policy engines expose different isolation primitives.",{},{"id":1159,"data":2248,"type":218,"tunes":2250},{"text":2249},"The required strength also changes with regulation, customer contracts, data sensitivity, threat model and operational scale. Some tenants may justify siloed databases or infrastructure while others share pooled resources.",{},{"id":1164,"data":2252,"type":218,"tunes":2254},{"text":2253},"The conceptual distinction does not change: permission to perform an operation is not the same thing as permission to cross a tenant boundary.",{},{"id":1169,"data":2256,"type":42,"tunes":2258},{"text":2257,"level":247},"Related canonical knowledge",{},{"id":1174,"data":2260,"type":218,"tunes":2262},{"text":2261},"S01 is a security-boundary prerequisite for Enterprise AI Architecture and AI Governance. Once AI tools, RAG or agents operate over multi-tenant data, tenant identity must travel through retrieval, tool execution, memory, caches and audit traces.",{},{"id":1179,"data":2264,"type":218,"tunes":2266},{"text":2265},"It also connects directly to Agentic AI: tool capability and role permission must still be constrained by tenant ownership before an agent can read or mutate business resources.",{},{"id":1184,"data":2268,"type":1190,"tunes":2272},{"url":1186,"title":2269,"excerpt":2270,"ctaLabel":2271},"MCP vs A2A vs UCP vs AP2 vs A2UI: The Agent Protocol Stack Explained","Protocol interoperability does not replace authorization or tenant isolation. Capability discovery and business authority remain separate architecture concerns.","Read the protocol stack article",{},{"id":1193,"data":2274,"type":218,"tunes":2276},{"text":2275},"For RAG, tenant isolation must be enforced before protected chunks reach model context.",{},{"id":1198,"data":2278,"type":1190,"tunes":2283},{"url":2279,"title":2280,"excerpt":2281,"ctaLabel":2282},"https:\u002F\u002Fstajic.de\u002Fblog\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works","What Is RAG? The Simplest Explanation of How It Works","The retrieval foundation for understanding where tenant-aware source filtering and vector-store isolation must be enforced.","Read the RAG foundation",{},{"id":1206,"data":2285,"type":42,"tunes":2287},{"text":2286,"level":247},"Frequently asked questions",{},{"id":1211,"data":2289,"type":1211,"tunes":2319},{"items":2290,"title":2318},[2291,2294,2297,2300,2303,2306,2309,2312,2315],{"id":1215,"answer":2292,"question":2293},"RBAC determines which operations a principal may perform. Tenant isolation determines which tenant's resources those operations may access. Secure multi-tenant applications normally need both.","What is the difference between RBAC and tenant isolation?",{"id":1219,"answer":2295,"question":2296},"No. ADMIN should have an explicit scope. A tenant administrator normally has broad permissions only inside that tenant, while cross-tenant platform administration should be modeled separately.","Does an ADMIN role automatically allow access to all tenants?",{"id":1223,"answer":2298,"question":2299},"No. Authentication proves identity. Authorization controls permitted actions. Tenant isolation additionally prevents those actions from reaching the wrong tenant's resources.","Is authentication enough for tenant isolation?",{"id":1227,"answer":2301,"question":2302},"It can be one input to tenant context, but the server must verify current membership\u002Fauthority and enforce the scope at protected resource boundaries. A claim alone does not replace isolation controls.","Should tenantId be stored in the JWT?",{"id":1231,"answer":2304,"question":2305},"Not necessarily. Shared-table, RLS, schema, database, infrastructure and hybrid isolation models can all be valid depending on risk and operational requirements.","Do I need a separate database per tenant?",{"id":1235,"answer":2307,"question":2308},"RLS can provide strong defense in depth, but correct database roles, request context, policy coverage and application-level authorization still matter.","Can PostgreSQL RLS replace tenant filters in application code?",{"id":1239,"answer":2310,"question":2311},"Tenant\u002Faccess scope should be enforced during retrieval so unauthorized chunks never enter model context. Preserve access metadata through chunking and indexing.","How should RAG enforce tenant isolation?",{"id":1243,"answer":2313,"question":2314},"Yes. This is common in B2B SaaS and is a strong reason to scope role assignments by tenant membership rather than treating roles as globally attached to the user.","Can one user have different roles in different tenants?",{"id":1247,"answer":2316,"question":2317},"Use negative cross-tenant tests: create at least two tenants, give a user valid permissions in one tenant, then prove every protected path denies access to the other tenant's resources.","What is the best test for tenant isolation?","RBAC vs tenant isolation FAQ",{},{"id":1253,"data":2321,"type":42,"tunes":2323},{"text":2322,"level":247},"Glossary",{},{"id":1258,"data":2325,"type":1258,"tunes":2360},{"title":2326,"entries":2327},"Key multi-tenant security terms",[2328,2330,2333,2335,2337,2340,2343,2346,2348,2351,2354,2357],{"term":395,"anchor":394,"definition":2329},"Role-Based Access Control: an authorization model that associates permissions with roles and assigns users or principals to those roles.",{"term":2331,"anchor":397,"definition":2332},"Tenant","A customer, organization, workspace or other isolated logical consumer of a shared multi-tenant system.",{"term":1592,"anchor":1268,"definition":2334},"Mechanisms that prevent one tenant from accessing, modifying or receiving another tenant's resources in a shared system.",{"term":1606,"anchor":1272,"definition":2336},"Verification of the identity of a user, service or other principal.",{"term":2338,"anchor":1276,"definition":2339},"Authorization","Decision process that determines whether a principal may perform a requested operation on a resource.",{"term":2341,"anchor":1280,"definition":2342},"Permission","A defined allowed operation or capability such as orders.read or users.write.",{"term":2344,"anchor":1284,"definition":2345},"Role","A named grouping of permissions associated with a responsibility or function.",{"term":1287,"anchor":1288,"definition":2347},"Attribute-Based Access Control: authorization based on attributes of the principal, resource, action or environment.",{"term":2349,"anchor":1292,"definition":2350},"Row-Level Security","Database policy mechanism that restricts which rows a database role or session may read or modify.",{"term":2352,"anchor":1296,"definition":2353},"Cross-tenant access","Any access path in which a principal operating under one tenant context reaches resources belonging to another tenant.",{"term":2355,"anchor":1300,"definition":2356},"Platform administrator","A privileged operational identity with explicitly modeled authority that may span multiple tenants.",{"term":2358,"anchor":1304,"definition":2359},"Tenant context","The verified tenant scope under which the current request, job or agent operation executes.",{},{"id":1308,"data":2362,"type":42,"tunes":2364},{"text":2363,"level":247},"Conclusion",{},{"id":1313,"data":2366,"type":218,"tunes":2368},{"text":2367},"RBAC and tenant isolation are complementary, not competing security mechanisms. RBAC structures operational permission; tenant isolation constrains the resource boundary inside which that permission can apply.",{},{"id":1318,"data":2370,"type":218,"tunes":2372},{"text":2371},"A robust multi-tenant request therefore needs more than “user has role ADMIN.” It needs a verified principal, verified tenant context, an allowed operation, a tenant-scoped target and enforcement at every resource layer that can carry tenant-owned data.",{},{"id":1323,"data":2374,"type":218,"tunes":2376},{"text":2375},"The shortest reliable rule is: authorize the action, then isolate the scope — and never assume one proves the other.",{},{"id":1328,"data":2378,"type":42,"tunes":2380},{"text":2379,"level":247},"Primary sources and current guidance",{},{"id":1333,"data":2382,"type":218,"tunes":2384},{"text":2383},"The sources below support the RBAC definition and current tenant-isolation guidance. The Aaasaasa AI CMS section is original implementation evidence and is intentionally bounded to the code patterns that were verified.",{},{"id":1338,"data":2386,"type":1345,"tunes":2391},{"link":1340,"meta":2387},{"image":2388,"title":2389,"description":2390},{"url":369},"NIST — Role Based Access Control","NIST overview of RBAC models and the INCITS RBAC standard, including users, roles, permissions, operations and objects.",{},{"id":1348,"data":2393,"type":1345,"tunes":2398},{"link":1350,"meta":2394},{"image":2395,"title":2396,"description":2397},{"url":369},"NIST CSRC — RBAC glossary","Current NIST glossary definitions of role-based access control as permission assignment through roles.",{},{"id":1357,"data":2400,"type":1345,"tunes":2405},{"link":1359,"meta":2401},{"image":2402,"title":2403,"description":2404},{"url":369},"AWS — The isolation mindset","AWS SaaS guidance explicitly distinguishing authentication\u002Fauthorization from tenant isolation and recommending shared isolation mechanisms.",{},{"id":1366,"data":2407,"type":1345,"tunes":2412},{"link":1368,"meta":2408},{"image":2409,"title":2410,"description":2411},{"url":369},"AWS — Multi-tenant authorization FAQ","Current guidance explaining the difference between authorization and tenant isolation in SaaS applications.",{},{"id":1375,"data":2414,"type":1345,"tunes":2419},{"link":1377,"meta":2415},{"image":2416,"title":2417,"description":2418},{"url":369},"AWS — Multi-tenant design considerations","Current SaaS guidance distinguishing tenant isolation from authorization and discussing pooled\u002Fsiloed authorization policy models.",{},{"id":1384,"data":2421,"type":1345,"tunes":2426},{"link":1386,"meta":2422},{"image":2423,"title":2424,"description":2425},{"url":369},"OWASP — Multi-Tenant Application Security Cheat Sheet","Current practical guidance for tenant context, database isolation, caches, storage, queues, testing and cross-tenant access prevention.",{},{"id":1393,"data":2428,"type":1345,"tunes":2433},{"link":1395,"meta":2429},{"image":2430,"title":2431,"description":2432},{"url":369},"OWASP — RAG Security Cheat Sheet","Current guidance requiring access control at retrieval time and tenant isolation for multi-tenant vector stores.",{},{"id":1402,"data":2435,"type":1345,"tunes":2440},{"link":1404,"meta":2436},{"image":2437,"title":2438,"description":2439},{"url":369},"OWASP — Authorization Regression Testing","Current testing guidance including role-demotion and cross-tenant boundary tests.",{},"2.31.6","RBAC controls what a user may do; tenant isolation controls which tenant’s resources that action may reach. Learn why multi-tenant SaaS security requires both boundaries.",{"lang":7,"title":208,"content":210,"contentJson":2444,"excerpt":1411},{"time":212,"blocks":2445,"version":1410},[2446,2449,2452,2455,2458,2461,2464,2467,2470,2473,2476,2479,2482,2485,2488,2491,2494,2497,2507,2510,2513,2516,2519,2522,2541,2544,2552,2555,2558,2561,2564,2567,2570,2573,2576,2579,2582,2585,2593,2596,2599,2602,2605,2608,2611,2622,2625,2628,2631,2634,2637,2640,2643,2646,2649,2652,2655,2658,2661,2664,2667,2670,2673,2676,2679,2682,2685,2688,2691,2694,2697,2700,2703,2706,2709,2712,2715,2718,2721,2724,2727,2730,2733,2736,2747,2750,2753,2756,2759,2762,2765,2768,2779,2782,2785,2788,2791,2794,2797,2812,2815,2818,2836,2839,2854,2857,2873,2876,2895,2898,2901,2904,2907,2910,2913,2916,2919,2922,2925,2928,2931,2934,2937,2940,2943,2946,2959,2962,2978,2981,2984,2987,2990,2993,2996,3001,3006,3011,3016,3021,3026,3031],{"id":215,"data":2447,"type":218,"tunes":2448},{"text":217},{},{"id":221,"data":2450,"type":226,"tunes":2451},{"body":223,"title":224,"variant":225},{},{"id":229,"data":2453,"type":226,"tunes":2454},{"body":231,"title":232,"variant":233},{},{"id":236,"data":2456,"type":226,"tunes":2457},{"body":238,"title":239,"variant":240},{},{"id":243,"data":2459,"type":248,"tunes":2460},{"title":245,"maxLevel":246,"minLevel":247},{},{"id":251,"data":2462,"type":42,"tunes":2463},{"text":253,"level":247},{},{"id":256,"data":2465,"type":218,"tunes":2466},{"text":258},{},{"id":261,"data":2468,"type":218,"tunes":2469},{"text":263},{},{"id":266,"data":2471,"type":218,"tunes":2472},{"text":268},{},{"id":271,"data":2474,"type":42,"tunes":2475},{"text":273,"level":247},{},{"id":276,"data":2477,"type":218,"tunes":2478},{"text":278},{},{"id":281,"data":2480,"type":218,"tunes":2481},{"text":283},{},{"id":286,"data":2483,"type":218,"tunes":2484},{"text":288},{},{"id":291,"data":2486,"type":42,"tunes":2487},{"text":293,"level":247},{},{"id":296,"data":2489,"type":218,"tunes":2490},{"text":298},{},{"id":301,"data":2492,"type":218,"tunes":2493},{"text":303},{},{"id":306,"data":2495,"type":218,"tunes":2496},{"text":308},{},{"id":311,"data":2498,"type":334,"tunes":2506},{"steps":2499,"title":332,"orientation":333},[2500,2501,2502,2503,2504,2505],{"label":315,"description":316},{"label":318,"description":319},{"label":321,"description":322},{"label":324,"description":325},{"label":327,"description":328},{"label":330,"description":331},{},{"id":337,"data":2508,"type":42,"tunes":2509},{"text":339,"level":247},{},{"id":342,"data":2511,"type":218,"tunes":2512},{"text":344},{},{"id":347,"data":2514,"type":218,"tunes":2515},{"text":349},{},{"id":352,"data":2517,"type":218,"tunes":2518},{"text":354},{},{"id":357,"data":2520,"type":42,"tunes":2521},{"text":359,"level":247},{},{"id":362,"data":2523,"type":399,"tunes":2540},{"rows":2524,"title":390,"layout":391,"columns":2537},[2525,2527,2529,2531,2533,2535],{"id":366,"label":367,"values":2526},[369,369],{"id":371,"label":372,"values":2528},[369,369],{"id":375,"label":376,"values":2530},[369,369],{"id":379,"label":380,"values":2532},[369,369],{"id":383,"label":384,"values":2534},[369,369],{"id":387,"label":388,"values":2536},[369,369],[2538,2539],{"id":394,"label":395},{"id":397,"label":398},{},{"id":402,"data":2542,"type":42,"tunes":2543},{"text":404,"level":247},{},{"id":407,"data":2545,"type":391,"tunes":2551},{"content":2546,"stretched":43,"withHeadings":14},[2547,2548,2549,2550],[411,412,413],[415,416,417],[419,420,421],[398,423,424],{},{"id":427,"data":2553,"type":218,"tunes":2554},{"text":429},{},{"id":432,"data":2556,"type":42,"tunes":2557},{"text":434,"level":247},{},{"id":437,"data":2559,"type":218,"tunes":2560},{"text":439},{},{"id":442,"data":2562,"type":218,"tunes":2563},{"text":444},{},{"id":447,"data":2565,"type":218,"tunes":2566},{"text":449},{},{"id":452,"data":2568,"type":42,"tunes":2569},{"text":454,"level":247},{},{"id":457,"data":2571,"type":218,"tunes":2572},{"text":459},{},{"id":462,"data":2574,"type":218,"tunes":2575},{"text":464},{},{"id":467,"data":2577,"type":218,"tunes":2578},{"text":469},{},{"id":472,"data":2580,"type":42,"tunes":2581},{"text":474,"level":247},{},{"id":477,"data":2583,"type":218,"tunes":2584},{"text":479},{},{"id":482,"data":2586,"type":391,"tunes":2592},{"content":2587,"stretched":43,"withHeadings":14},[2588,2589,2590,2591],[486,487],[489,490],[492,493],[495,496],{},{"id":499,"data":2594,"type":218,"tunes":2595},{"text":501},{},{"id":504,"data":2597,"type":42,"tunes":2598},{"text":506,"level":247},{},{"id":509,"data":2600,"type":218,"tunes":2601},{"text":511},{},{"id":514,"data":2603,"type":218,"tunes":2604},{"text":516},{},{"id":519,"data":2606,"type":226,"tunes":2607},{"body":521,"title":522,"variant":523},{},{"id":526,"data":2609,"type":42,"tunes":2610},{"text":528,"level":247},{},{"id":531,"data":2612,"type":391,"tunes":2621},{"content":2613,"stretched":43,"withHeadings":14},[2614,2615,2616,2617,2618,2619,2620],[535,536,537],[539,540,541],[543,544,545],[547,548,549],[551,552,553],[555,556,557],[559,560,561],{},{"id":564,"data":2623,"type":218,"tunes":2624},{"text":566},{},{"id":569,"data":2626,"type":42,"tunes":2627},{"text":571,"level":247},{},{"id":574,"data":2629,"type":218,"tunes":2630},{"text":576},{},{"id":579,"data":2632,"type":218,"tunes":2633},{"text":581},{},{"id":584,"data":2635,"type":218,"tunes":2636},{"text":586},{},{"id":589,"data":2638,"type":42,"tunes":2639},{"text":591,"level":247},{},{"id":594,"data":2641,"type":218,"tunes":2642},{"text":596},{},{"id":599,"data":2644,"type":218,"tunes":2645},{"text":601},{},{"id":604,"data":2647,"type":218,"tunes":2648},{"text":606},{},{"id":609,"data":2650,"type":42,"tunes":2651},{"text":611,"level":247},{},{"id":614,"data":2653,"type":218,"tunes":2654},{"text":616},{},{"id":619,"data":2656,"type":218,"tunes":2657},{"text":621},{},{"id":624,"data":2659,"type":218,"tunes":2660},{"text":626},{},{"id":629,"data":2662,"type":42,"tunes":2663},{"text":631,"level":247},{},{"id":634,"data":2665,"type":218,"tunes":2666},{"text":636},{},{"id":639,"data":2668,"type":218,"tunes":2669},{"text":641},{},{"id":644,"data":2671,"type":218,"tunes":2672},{"text":646},{},{"id":649,"data":2674,"type":42,"tunes":2675},{"text":651,"level":247},{},{"id":654,"data":2677,"type":218,"tunes":2678},{"text":656},{},{"id":659,"data":2680,"type":218,"tunes":2681},{"text":661},{},{"id":664,"data":2683,"type":218,"tunes":2684},{"text":666},{},{"id":669,"data":2686,"type":226,"tunes":2687},{"body":671,"title":672,"variant":233},{},{"id":675,"data":2689,"type":42,"tunes":2690},{"text":677,"level":247},{},{"id":680,"data":2692,"type":218,"tunes":2693},{"text":682},{},{"id":685,"data":2695,"type":218,"tunes":2696},{"text":687},{},{"id":690,"data":2698,"type":42,"tunes":2699},{"text":692,"level":247},{},{"id":695,"data":2701,"type":218,"tunes":2702},{"text":697},{},{"id":700,"data":2704,"type":218,"tunes":2705},{"text":702},{},{"id":705,"data":2707,"type":218,"tunes":2708},{"text":707},{},{"id":710,"data":2710,"type":42,"tunes":2711},{"text":712,"level":247},{},{"id":715,"data":2713,"type":218,"tunes":2714},{"text":717},{},{"id":720,"data":2716,"type":218,"tunes":2717},{"text":722},{},{"id":725,"data":2719,"type":218,"tunes":2720},{"text":727},{},{"id":730,"data":2722,"type":42,"tunes":2723},{"text":732,"level":247},{},{"id":735,"data":2725,"type":218,"tunes":2726},{"text":737},{},{"id":740,"data":2728,"type":218,"tunes":2729},{"text":742},{},{"id":745,"data":2731,"type":218,"tunes":2732},{"text":747},{},{"id":750,"data":2734,"type":42,"tunes":2735},{"text":752,"level":247},{},{"id":755,"data":2737,"type":391,"tunes":2746},{"content":2738,"stretched":43,"withHeadings":14},[2739,2740,2741,2742,2743,2744,2745],[759,760,761,762],[764,765,766,767],[764,765,769,770],[764,772,766,773],[764,772,769,770],[776,777,778,779],[781,782,783,784],{},{"id":787,"data":2748,"type":42,"tunes":2749},{"text":789,"level":247},{},{"id":792,"data":2751,"type":226,"tunes":2752},{"body":794,"title":795,"variant":240},{},{"id":798,"data":2754,"type":218,"tunes":2755},{"text":800},{},{"id":803,"data":2757,"type":218,"tunes":2758},{"text":805},{},{"id":808,"data":2760,"type":218,"tunes":2761},{"text":810},{},{"id":813,"data":2763,"type":218,"tunes":2764},{"text":815},{},{"id":818,"data":2766,"type":218,"tunes":2767},{"text":820},{},{"id":823,"data":2769,"type":391,"tunes":2778},{"content":2770,"stretched":43,"withHeadings":14},[2771,2772,2773,2774,2775,2776,2777],[827,828],[830,831],[833,834],[836,837],[839,840],[842,843],[845,846],{},{"id":849,"data":2780,"type":226,"tunes":2781},{"body":851,"title":852,"variant":233},{},{"id":855,"data":2783,"type":42,"tunes":2784},{"text":857,"level":247},{},{"id":860,"data":2786,"type":218,"tunes":2787},{"text":862},{},{"id":865,"data":2789,"type":218,"tunes":2790},{"text":867},{},{"id":870,"data":2792,"type":218,"tunes":2793},{"text":872},{},{"id":875,"data":2795,"type":42,"tunes":2796},{"text":877,"level":247},{},{"id":880,"data":2798,"type":391,"tunes":2811},{"content":2799,"stretched":43,"withHeadings":14},[2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810],[884,885],[887,888],[890,891],[893,894],[896,897],[899,900],[902,903],[905,906],[908,909],[911,912],[914,915],{},{"id":918,"data":2813,"type":218,"tunes":2814},{"text":920},{},{"id":923,"data":2816,"type":42,"tunes":2817},{"text":925,"level":247},{},{"id":928,"data":2819,"type":391,"tunes":2835},{"content":2820,"stretched":43,"withHeadings":14},[2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834],[932,933],[935,936],[938,939],[941,942],[944,945],[947,948],[950,951],[953,954],[956,957],[959,960],[962,963],[965,966],[968,969],[971,972],{},{"id":975,"data":2837,"type":42,"tunes":2838},{"text":977,"level":247},{},{"id":980,"data":2840,"type":391,"tunes":2853},{"content":2841,"stretched":43,"withHeadings":14},[2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852],[984,985],[987,988],[990,991],[993,994],[996,997],[999,1000],[1002,1003],[1005,1006],[1008,1009],[1011,1012],[1014,1015],{},{"id":1018,"data":2855,"type":42,"tunes":2856},{"text":1020,"level":247},{},{"id":1023,"data":2858,"type":334,"tunes":2872},{"steps":2859,"title":1062,"orientation":333},[2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871],{"label":1027,"description":1028},{"label":1030,"description":1031},{"label":1033,"description":1034},{"label":1036,"description":1037},{"label":1039,"description":1040},{"label":1042,"description":1043},{"label":1045,"description":1046},{"label":1048,"description":1049},{"label":1051,"description":1052},{"label":1054,"description":1055},{"label":1057,"description":1058},{"label":1060,"description":1061},{},{"id":1065,"data":2874,"type":42,"tunes":2875},{"text":1067,"level":247},{},{"id":1070,"data":2877,"type":391,"tunes":2894},{"content":2878,"stretched":43,"withHeadings":14},[2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893],[412,1074],[1076,1077],[1079,1080],[1082,1083],[1085,1086],[1088,1089],[1091,1092],[1094,1095],[1097,1098],[1100,1101],[1103,1104],[1106,1107],[1109,1110],[1112,1113],[1115,1116],{},{"id":1119,"data":2896,"type":42,"tunes":2897},{"text":1121,"level":247},{},{"id":1124,"data":2899,"type":218,"tunes":2900},{"text":1126},{},{"id":1129,"data":2902,"type":218,"tunes":2903},{"text":1131},{},{"id":1134,"data":2905,"type":218,"tunes":2906},{"text":1136},{},{"id":1139,"data":2908,"type":218,"tunes":2909},{"text":1141},{},{"id":1144,"data":2911,"type":218,"tunes":2912},{"text":1146},{},{"id":1149,"data":2914,"type":42,"tunes":2915},{"text":1151,"level":247},{},{"id":1154,"data":2917,"type":218,"tunes":2918},{"text":1156},{},{"id":1159,"data":2920,"type":218,"tunes":2921},{"text":1161},{},{"id":1164,"data":2923,"type":218,"tunes":2924},{"text":1166},{},{"id":1169,"data":2926,"type":42,"tunes":2927},{"text":1171,"level":247},{},{"id":1174,"data":2929,"type":218,"tunes":2930},{"text":1176},{},{"id":1179,"data":2932,"type":218,"tunes":2933},{"text":1181},{},{"id":1184,"data":2935,"type":1190,"tunes":2936},{"url":1186,"title":1187,"excerpt":1188,"ctaLabel":1189},{},{"id":1193,"data":2938,"type":218,"tunes":2939},{"text":1195},{},{"id":1198,"data":2941,"type":1190,"tunes":2942},{"url":1200,"title":1201,"excerpt":1202,"ctaLabel":1203},{},{"id":1206,"data":2944,"type":42,"tunes":2945},{"text":1208,"level":247},{},{"id":1211,"data":2947,"type":1211,"tunes":2958},{"items":2948,"title":1250},[2949,2950,2951,2952,2953,2954,2955,2956,2957],{"id":1215,"answer":1216,"question":1217},{"id":1219,"answer":1220,"question":1221},{"id":1223,"answer":1224,"question":1225},{"id":1227,"answer":1228,"question":1229},{"id":1231,"answer":1232,"question":1233},{"id":1235,"answer":1236,"question":1237},{"id":1239,"answer":1240,"question":1241},{"id":1243,"answer":1244,"question":1245},{"id":1247,"answer":1248,"question":1249},{},{"id":1253,"data":2960,"type":42,"tunes":2961},{"text":1255,"level":247},{},{"id":1258,"data":2963,"type":1258,"tunes":2977},{"title":1260,"entries":2964},[2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976],{"term":395,"anchor":394,"definition":1263},{"term":1265,"anchor":397,"definition":1266},{"term":398,"anchor":1268,"definition":1269},{"term":1271,"anchor":1272,"definition":1273},{"term":1275,"anchor":1276,"definition":1277},{"term":1279,"anchor":1280,"definition":1281},{"term":1283,"anchor":1284,"definition":1285},{"term":1287,"anchor":1288,"definition":1289},{"term":1291,"anchor":1292,"definition":1293},{"term":1295,"anchor":1296,"definition":1297},{"term":1299,"anchor":1300,"definition":1301},{"term":1303,"anchor":1304,"definition":1305},{},{"id":1308,"data":2979,"type":42,"tunes":2980},{"text":1310,"level":247},{},{"id":1313,"data":2982,"type":218,"tunes":2983},{"text":1315},{},{"id":1318,"data":2985,"type":218,"tunes":2986},{"text":1320},{},{"id":1323,"data":2988,"type":218,"tunes":2989},{"text":1325},{},{"id":1328,"data":2991,"type":42,"tunes":2992},{"text":1330,"level":247},{},{"id":1333,"data":2994,"type":218,"tunes":2995},{"text":1335},{},{"id":1338,"data":2997,"type":1345,"tunes":3000},{"link":1340,"meta":2998},{"image":2999,"title":1343,"description":1344},{"url":369},{},{"id":1348,"data":3002,"type":1345,"tunes":3005},{"link":1350,"meta":3003},{"image":3004,"title":1353,"description":1354},{"url":369},{},{"id":1357,"data":3007,"type":1345,"tunes":3010},{"link":1359,"meta":3008},{"image":3009,"title":1362,"description":1363},{"url":369},{},{"id":1366,"data":3012,"type":1345,"tunes":3015},{"link":1368,"meta":3013},{"image":3014,"title":1371,"description":1372},{"url":369},{},{"id":1375,"data":3017,"type":1345,"tunes":3020},{"link":1377,"meta":3018},{"image":3019,"title":1380,"description":1381},{"url":369},{},{"id":1384,"data":3022,"type":1345,"tunes":3025},{"link":1386,"meta":3023},{"image":3024,"title":1389,"description":1390},{"url":369},{},{"id":1393,"data":3027,"type":1345,"tunes":3030},{"link":1395,"meta":3028},{"image":3029,"title":1398,"description":1399},{"url":369},{},{"id":1402,"data":3032,"type":1345,"tunes":3035},{"link":1404,"meta":3033},{"image":3034,"title":1407,"description":1408},{"url":369},{},"Post erfolgreich abgerufen",{"items":3038,"source":3123,"manualIds":3124,"manualMatchedIds":3125},[3039,3046,3053,3060,3067,3074,3081,3088,3095,3102,3109,3116],{"id":3040,"slug":3041,"title":3042,"excerpt":3043,"featuredImage":3044,"publishedAt":3045},"495","sovereign-ai-control-of-models-data-infrastructure-and-dependencies","主权人工智能：模型、数据、基础设施与依赖关系的控制","主权人工智能关乎对模型、数据、基础设施、软件、运营和战略依赖的有效控制——而不仅仅是人工智能模型托管在哪里。","\u002Fuploads\u002F2026\u002F10\u002Fsovereign-ai-control-of-models-data-infrastructure-and-dependencies-1791488833132-niy85x.webp","2026-10-08T15:45:00.000Z",{"id":3047,"slug":3048,"title":3049,"excerpt":3050,"featuredImage":3051,"publishedAt":3052},"478","what-is-rag-the-simplest-explanation-of-how-it-works","什么是RAG？对其工作原理的最简单解释","RAG听起来很复杂，但想法很简单：在AI回答之前，它先从知识源查找有用的信息，并将该信息提供给语言模型。本指南使用一个简单的思维模型来解释RAG、LLM、状态、记忆和工具。","\u002Fuploads\u002F2026\u002F09\u002Fwhat-is-rag-the-simplest-explanation-of-how-it-works-1790377492124-khjagt.webp","2026-09-25T19:03:00.000Z",{"id":3054,"slug":3055,"title":3056,"excerpt":3057,"featuredImage":3058,"publishedAt":3059},"472","why-more-context-can-make-ai-answers-worse","为什么更多上下文会让AI的回答更糟","更大的上下文窗口并不保证更好的答案。本文解释了信号稀释、证据冲突、状态过时、位置敏感性和有损压缩如何降低AI可靠性——并介绍了一种实用的上下文压力测试。","\u002Fuploads\u002F2026\u002F09\u002Fwhy-more-context-can-make-ai-answers-worse-1790351615793-2ntv2v.webp","2026-09-25T11:51:00.000Z",{"id":3061,"slug":3062,"title":3063,"excerpt":3064,"featuredImage":3065,"publishedAt":3066},"470","what-should-an-ai-agent-remember-forget-recompute-or-retrieve-again","AI代理应该记住、遗忘、重新计算还是再次检索什么？","长时间运行的代理不应记住所有内容。本文提供了一个实用的生命周期模型，用于决定哪些内容应属于持久记忆、哪些内容应重新检索、哪些内容重新计算更安全，以及哪些内容应过期或被取代。","\u002Fuploads\u002F2026\u002F09\u002Fwhat-should-an-ai-agent-remember-forget-recompute-or-retrieve-again-1790351131087-iehz28.webp","2026-09-25T09:43:00.000Z",{"id":3068,"slug":3069,"title":3070,"excerpt":3071,"featuredImage":3072,"publishedAt":3073},"471","how-to-know-whether-an-ai-agent-actually-used-the-right-evidence","如何判断一个AI智能体是否真正使用了正确的证据","AI代理可以引用来源，却仍然使用错误的证据。本文介绍一种实用方法，用于核查主张支持、来源权威性、适用性、出处，以及证据是否实际影响了答案。","\u002Fuploads\u002F2026\u002F09\u002Fhow-to-know-whether-an-ai-agent-actually-used-the-right-evidence-1790351317188-o5z9ve.webp","2026-09-25T11:47:00.000Z",{"id":3075,"slug":3076,"title":3077,"excerpt":3078,"featuredImage":3079,"publishedAt":3080},"487","vector-databases-embeddings-and-reranking-three-different-parts-of-retrieval","向量数据库、嵌入和重排序：检索的三个不同部分","嵌入表示含义，向量数据库检索候选结果，重排序器则精炼结果。了解这三个检索层在RAG中如何不同并协同工作。","\u002Fuploads\u002F2026\u002F10\u002Fvector-databases-embeddings-and-reranking-three-different-parts-of-retrieval-1791480129884-9dtasz.webp","2026-10-08T11:21:00.000Z",{"id":3082,"slug":3083,"title":3084,"excerpt":3085,"featuredImage":3086,"publishedAt":3087},"486","source-of-truth-in-ai-systems-where-reliable-knowledge-actually-comes-from","AI系统中的真相来源：可靠知识究竟从何而来","事实来源（Source of Truth）定义了对于特定事实或状态，哪个来源具有权威性。了解它与RAG、溯源、记忆、上下文、向量数据库和记录系统有何不同。","\u002Fuploads\u002F2026\u002F10\u002Fsource-of-truth-in-ai-systems-where-reliable-knowledge-actually-comes-from-1791479103235-6bq9em.webp","2026-10-08T13:02:00.000Z",{"id":3089,"slug":3090,"title":3091,"excerpt":3092,"featuredImage":3093,"publishedAt":3094},"479","where-does-an-llm-get-its-data-rag-data-sources-in-python","LLM从哪里获取数据？Python中的RAG数据源","LLM 并不会神奇地知道你的文件、数据库或 API。这个 RAG 系列的实用续篇用简单的 Python 展示了外部数据如何变成可检索的证据：从文本文件和 SQL 到全文搜索、嵌入、上下文组装以及最终的 LLM 调用。","\u002Fuploads\u002F2026\u002F09\u002Fwhere-does-an-llm-get-its-data-rag-data-sources-in-python-1790517200521-nfsi5i.webp","2026-09-27T05:51:00.000Z",{"id":3096,"slug":3097,"title":3098,"excerpt":3099,"featuredImage":3100,"publishedAt":3101},"476","mcp-vs-a2a-vs-ucp-vs-ap2-vs-a2ui-the-agent-protocol-stack-explained","MCP vs A2A vs UCP vs AP2 vs A2UI：智能体协议栈详解","MCP、A2A、UCP、AP2 和 A2UI 常被描述为相互竞争的智能体标准。它们大多解决的是不同的互操作性问题。本指南将每个协议映射到其实际标准化的边界，并展示它们如何在同一个生产系统中协同工作。","\u002Fuploads\u002F2026\u002F09\u002Fmcp-vs-a2a-vs-ucp-vs-ap2-vs-a2ui-the-agent-protocol-stack-explained-1790352625869-2ezle0.webp","2026-09-25T12:09:00.000Z",{"id":3103,"slug":3104,"title":3105,"excerpt":3106,"featuredImage":3107,"publishedAt":3108},"364","tipps-fuer-die-verbesserung-der-seo-suchmaschinenoptimierung","Mastering the SEO Workflow: Essential Optimization Strategies for Organic Growth","A structured SEO workflow is crucial for sustainable organic growth. Learn the ten foundational strategies, from keyword research and technical optimization to content quality and performance analysis.","\u002Fuploads\u002F2026\u002F03\u002Ftipps-fuer-die-verbesserung-der-seo-suchmaschinenoptimierung-1774866098131-hwkzrg.webp","2024-01-26T06:35:00.000Z",{"id":3110,"slug":3111,"title":3112,"excerpt":3113,"featuredImage":3114,"publishedAt":3115},"467","the-answer-validity-boundary-the-missing-layer-between-relevance-and-reliable-ai-answers","答案有效性边界：相关性到可靠AI答案之间缺失的层级","一个来源可能相关、权威，但对于所提出的问题仍然是错误的。缺失的层次是适用性：答案成立的条件，以及迫使其被重新考虑的变化。本文介绍了“答案有效性边界”这一面向人类、AI搜索和RAG系统的来源设计模式。","\u002Fuploads\u002F2026\u002F09\u002Fthe-answer-validity-boundary-the-missing-layer-between-relevance-and-reliable-ai-answers-1790272901306-1g5jly.webp","2026-09-24T11:59:00.000Z",{"id":3117,"slug":3118,"title":3119,"excerpt":3120,"featuredImage":3121,"publishedAt":3122},"484","what-is-an-ai-platform-architect-models-data-runtime-security-and-operations","什么是AI平台架构师？模型、数据、运行时、安全与运维","AI平台架构师负责跨模型、提供商、检索、智能体、身份、安全、评估、可观测性和运营设计可复用的AI基础。","\u002Fuploads\u002F2026\u002F10\u002Fwhat-is-an-ai-platform-architect-models-data-runtime-security-and-operations-1791477229171-ou3zcc.webp","2026-10-08T12:32:00.000Z","fallback",[],[]]