Lurno 如何让一个组织的数据不被另一个组织看到
Lurno 对每个会改动数据的请求做三次彼此独立的授权。界面在渲染某个控件之前先检查权限。服务端在触及数据之前断言同一项权限,答案为否即拒绝。数据库再应用一条行级安全策略,决定这次查询究竟能返回哪些行。三者必须全部通过。这样的策略共有 868 条,分布在 676 次迁移中,应用数据表位于 14 个领域 schema 中,而不是默认的 public schema,因此即便上层代码写错了,一个组织的数据行在另一个组织的会话中仍然不可达。管理性变更会写入只可追加的审计日志,日志行之间用 SHA-256 串成链,可以用一条查询来验证。Augmental Learning Inc. 对齐 ISO 27001 实践;它没有 ISO 27001 证书,也没有 SOC 2 报告,我们会在问卷里如实写明,而不是让买家自行假设。
- 三重授权
- 一种模型:同一个请求被三种彼此独立失效的机制授权三次。第一重是界面:它会隐藏当前登录者没有权限使用的控件。第二重是服务端:处理函数在触及数据之前断言权限,答案为否即抛出错误。第三重是数据库:表上的行级安全策略限制查询能返回哪些行。第一重是便利,第二重是主要边界,第三重是在第二重被绕过时仍然守得住的那一层。
三道关卡,以及每一道背后是什么
一个请求,授权三次
界面里的控件在渲染前先问当前登录者是否持有某项权限。服务端的处理函数在做任何事之前断言同一项权限。随后数据库应用一条策略,决定这次查询能看到哪些行。三种机制,三处必须各自正确,其中任何一处说不,请求就结束。
- 界面检查是便利,不是边界。它隐藏一个按钮,并不保护一张表。
- 每次检查都经由同一套权限目录和同一个函数解析。没有哪个处理函数会读取角色名,然后自行决定那个角色意味着什么。
- 在组织树某个分支上授予的角色沿该分支向下级联——而数据库策略读取的是与界面相同的那棵树,因此两者不可能各说各话。
676 次迁移中的 868 条策略
隔离是 schema,不是约定。表在创建时就启用行级安全,并配上把判断委托给服务端所调用的同一个权限函数的策略,另有一项迁移检查,会找出被授予访问权却没有对应策略的表。这个数字不是营销数据——它就是你去问数据库“你正在执行多少条策略”时返回的结果。
- 策略不内联自己的逻辑。它们调用权限函数,因此答案不会和服务端上一刻的判断产生偏差。
- 写策略除读取条件外还带有检查条件,因此插入操作无法把一行数据放进写入者没有权限的组织。
- 凡是视图暴露个人数据的地方,都逐列授予访问权。表级授权会悄悄抵消列级保护,所以我们不用它。
十四个领域 schema,从不用 public
应用数据表位于十四个具名 schema 中——身份与访问一个、组织一个、媒体一个,依此类推。真正要紧的东西都不在默认的 public schema 里,而那正是一次误授权或一个宽松默认值最容易造成暴露的地方。私有媒体对已登录的浏览器根本没有存储策略:每一次读取都由先检查了归属行的服务端签发,每一次上传也以同样方式签发。
- 一次性令牌——邀请、密码重置、账号找回——以加盐哈希存储。原始令牌只在邮件里出现一次,此后不再出现。
- 只有品牌资产是公开的。组织的标志和站点图标必须在任何人登录之前就能显示;头像和课时媒体不需要,因此保持签名访问。
事后证明发生过什么
没人能核查的审计日志,只是包装更好的日志文件。这一份是只可追加、可发现篡改的,而核查它就是一条查询。
只可追加的日志
管理性变更以事件形式写入,带有操作者、动作、资源、组织,以及变更前后的数据。没有任何操作会更新审计行。写入路径只做追加。
SHA-256 哈希链
每个事件都存储前一个事件的哈希和自身的哈希,两者都由数据库触发器赋值,而不是由记录该事件的代码赋值。改动其中一行,之后的每个哈希都会对不上。
可以当场看着跑的验证
一个验证函数会沿着链走一遍,指出第一处断裂所在的行。评审时我们会当着你的面运行它。
访问权限复核
谁在哪个组织里持有哪个角色,按计划定期复核,而不是等到审计时才看。一次移除和其他操作一样,也是一条审计事件。
破坏性操作需要两个人
匿名化或删除一个人先是一次申请,然后是一次单独的批准。申请人不能批准自己的申请,任何人都不能把自己作为对象。
你可以结束的会话
已登录的人可以撤销自己的其他会话,被撤销的会话会在下一次权限检查时被拦住,而不是等到令牌自然过期。
从同意到删除,每一步都有时钟
每个租户是其学习者数据的控制者,Lurno 是处理者。下面这套机制让这种划分成为事实,而不只是合同上的措辞。
- 01
带版本的同意
一个人同意的每份政策都带有版本号。政策一变,旧的同意即失效:会再次征询本人,并记录他同意了什么、在什么时候。AI 处理是单独的一项同意——撤回它,就不会有任何内容发往任何服务商。
- 02
以向导形式完成的数据主体访问请求
管理员按流程走完请求,而不是临场发挥:确认主体身份、收集平台上持有的全部数据、生成导出文件。可携带意味着机器可读——JSON 和 CSV,而不是一份截图的 PDF。
- 03
有终止日期的留存
个人数据按类别设有留存期,而不是默认永久保存。停用账号、过期邀请和陈旧会话,都有一个此后即不再存在的日期。
- 04
需两人授权的删除
一名管理员发起,另一名批准,之后才会执行。发起人永远不能批准,两人也都不能把自己作为对象。删除会触及引用该人的那些表,而不只是资料行。
- 05
带 72 小时时钟的事件登记
一起事件就是一行记录,带有从发现时刻起算 72 小时的截止时间,以及在关闭之前会持续触发的提醒。时钟从发现开始走,而不是从有人想起第 33 条的那一刻。
数据实际存放在哪里
可以指向别处的媒体存储
文件通过一个存储接口写入,该接口有四种实现:Supabase Storage、Amazon S3、Azure Blob Storage 和 Google Cloud Storage。对于数据驻留要求,这通常就是诚实的答案——一次部署可以把文件写进你被要求使用的那个地区的存储桶,而不必等供应商去开一个地区。请尽早告诉我们你的要求,我们会明确说明今天能否满足。
- 数据库、认证以及 API 所运行的函数由 Supabase 托管。那是你无法通过配置绕开的唯一依赖,它在 DPA 中被具名列出。
- 各组织的自定义域名通过 Cloudflare 提供服务,证书自动签发,因此贝鲁特或米兰的学习者看到的是你的域名,而不是我们的。
产品分析在欧盟,且不包含学习者
平台分析通过 PostHog 的欧盟区域运行,外面包了一层抽象,因此更换供应商不必改动产品。会话回放经过遮罩处理,并且从不记录学习者——学习者界面根本没有接入回放。
- 文本输入以及任何被标记为个人数据的内容,都会在浏览器中、在回放发往任何地方之前先被遮罩。
- 分析受同意管控,除非组织主动开启,否则处于关闭状态。在任何界面上,都不会对未成年人做画像。
文本在抵达 AI 服务商之前会经历什么
学习者的一条消息、一份上传的 PDF、在助手里敲下的一个问题:这些都是内容,没有一样是指令。这个区分是被强制执行的,而不是在提示词里请求的。
注入分类
不受信任的输入会在真正的调用发生之前先被分类。试图引导模型转向的文本会被标记,而不是被执行。
随机化围栏
不受信任的文本被包在一个它猜不到的、每次请求都不同的标签里,而该标签会从内容本身中剥除。截断时会重新闭合围栏,而不是让它敞着。
调用前脱敏
姓名、邮箱和标识符在任何内容发往服务商之前就被替换。批改是在匿名化后的作答上进行的;回到学习者本人的对照关系留在我们的服务器上。
输出结构校验
每一个响应都要按 schema 校验。格式不合规的回复只有一次修复机会,随后即失败,而不会流入课程。
从提议到变更的完整轨迹
请求、被采纳的草稿和被拒绝的草稿,是同一份哈希链日志中的不同条目。模型提议了什么,就摆在有人实际采用了什么的旁边。
用户如何登录
按安全评审人员需要的方式写:今天有什么,以及没有什么。
账号通过邀请创建
账号由管理员创建或通过邀请创建——没有自助注册。重置和找回链接是一次性的,并以哈希形式存储。
合作方登录(静默 SSO)
已经完成认证的合作方系统,可以用一份签名断言把用户移交过来,学习者不会看到第二次登录。它按组织配置,使用密钥,并且可撤销。
SAML 和 OIDC 单点登录
规划中尚未开发。如果你的上线依赖 Entra ID 或 Okta,请在第一次通话时说明,我们会告诉你它的进展,而不是暗示它已经有了。
MFA 与通行密钥
规划中同样在路线图上。今天由身份提供方处理密码,会话可由本人撤销,撤销会在下一次权限检查时生效。
所有会接触你数据的一方
共五家,每一家都在数据处理协议中具名列出,而不是事后才被发现。
| Capability | 它负责什么 | 适用范围 |
|---|---|---|
| Supabase | 数据库、认证、文件存储,以及 API 所运行的函数 | 主要处理者。媒体存储可以改指向 S3、Azure 或 GCS。 |
| Cloudflare | DNS、TLS,以及各组织所使用的自定义域名 | 为各组织域名终结 TLS;证书自动签发。 |
| OpenAI | AI 生成、辅导和初评草稿 | 仅在请求需要时调用,且在脱敏之后。也可以改配置为 Anthropic 或 Google,组织还可以接入自己的密钥。 |
| Resend | 事务性邮件——邀请、通知、重置 | 组织可以用自己的子域名和自己的密钥发送。 |
| PostHog | 产品分析和经过遮罩的会话回放 | 欧盟区域。学习者界面不被录制。 |
具有约束力的清单是数据处理协议中的那一份,另有面向学校的 FERPA 学生数据隐私附录。我们会在通话之前把两份都发给你,而不是通话之后。
WCAG 2.1 AA,以及我们没有的东西
Lurno 按 WCAG 2.1 AA 构建。自动化 axe 检查在持续集成中运行,因此一次对比度不达标或一个缺失的标签会让构建失败,而不会进入发布版本。键盘操作路径、可见焦点和减少动效偏好都在组件库里实现,而不是逐个页面事后补上。产品提供英语、法语、阿拉伯语和意大利语,阿拉伯语全程从右至左,而不是把从左至右的布局翻译一遍。
我们没有的是 VPAT 和第三方无障碍审计,我们宁愿写在这里,也不想把它埋进第 47 题的答案里。如果一份正式的合规报告是采购的前提条件,请尽早提出——那是一次范围界定的讨论,不是一个勾选框。