Malla 在客户密钥旁边运行着不可信的内容、用户公式和访客输入。以下这些边界让它们彼此隔离。
两类用户,绝不混用
编辑器用户和站点访客使用不同的表、不同的会话 cookie 和不同的签名密钥。编辑器会话是 HTTP-only、Secure、SameSite=Lax 的 cookie,并带有 CSRF 检查;密码用 scrypt 哈希。访客会话的作用域限定在客户的域名上,存放在站点自己的数据库中。
授权
- 每个 api 路由都会检查调用者在该站点上的角色;未知站点和无权访问的站点都返回 404。
- 发布到生产环境、修改 slug、管理域名和写入集成都需要管理员。
- 实时房间会验证短期令牌和页面所属站点;查看者只读,内容编辑者只能修改文本。
- Realtime 在存储或转发每个更新之前,都会按结构定义进行校验。
表达式
没有 eval,也没有 new Function。解释器拒绝 window、document、globalThis、constructor、__proto__ 和 prototype,不支持赋值和循环,并限制源码长度、深度、求值节点数、字符串和数组大小。服务端也用同一个解释器求值行规则和页面访问规则。
浏览器不可信
客户端工作流和绑定可以被访客读取和修改,因此它们从不拥有任何权限。页面访问在服务端强制执行,受限页面的客户端查询要通过同样的关卡,写入则通过服务端工作流和行规则。在规则中,匿名 user 带有 id: NaN,因此所有权检查绝不会匹配没有所有者的行。
出站请求
集成只能访问它们声明的主机。服务端请求要求 HTTPS,通过 DNS-over-HTTPS 解析主机名,拦截私有、回环和链路本地地址(重定向会重新检查),并限制时间和响应大小。runJs 在没有绑定、没有密钥的 Worker Loader 隔离环境中运行。
样式和 HTML
可能跳出规则的样式值会被拒绝;属性名会经过校验。渲染器会转义文本并净化 URL。富文本以结构化 JSON 存储,绝不存为原始 HTML。站点自定义代码只在已发布站点上运行,绝不在编辑器中运行。
防滥用
表单使用 Turnstile、蜜罐以及按 IP 和按表单的限制,并以哈希形式存储 IP。公共端点、客户端查询、登录和注册使用 Cloudflare 限流。