安全
嵌入智能体的隔离边界、令牌与来源白名单、哪些内容不是秘密,以及 CSP、SRI 配置。
嵌入把一个智能体放进你的页面,页面的访问者就是智能体的使用者。这一页说明平台替你守住了什么、哪些要你自己守,以及宿主页怎样配置。
责任划分
| 平台保证 | 你负责 |
|---|---|
| 嵌入令牌只能访问一个智能体下自己名下的会话 | 用你自己的登录态确定 external_user_id,不要信浏览器传来的值 |
| 越权访问一律返回 404,不透露资源是否存在 | 工具服务端按终端用户鉴权(工具授权) |
| 令牌只在浏览器内存里,短期有效,可以随时撤销 | 保管 API Key,只在后端使用 |
| 只接受白名单来源的页面使用令牌 | 配好 allowed_origins,宿主页配好 CSP |
隔离边界
- 令牌的主体是终端用户,不是你的组织。持有令牌的人只能创建和读取自己名下的会话,看不到同一智能体下其他用户的会话,也不能调用签发、撤销、列出令牌这类宿主接口(返回 404)。身份来自令牌,不来自请求参数。
- 跨用户、跨智能体一律 404,而不是 403:不告诉访问者「这个东西存在但不属于你」。
- API Key 永远不进浏览器。后端用它签发令牌;浏览器只拿令牌。令牌的签发与撤销见令牌与终端用户。
令牌
- 令牌有效期 60 到 3600 秒。设短一些:被截获的令牌价值有限。
getToken会在到期前被再次调用,换发时再确认一次用户仍处于登录状态。 - 令牌只存在于内存,不要自己写进
localStorage、Cookie 或页面 HTML。 - 发现泄露或用户登出时,按签发记录的
id撤销,令牌立即失效,进行中的事件流会收到EMBED_TOKEN_REVOKED并关闭。 - 对某个用户启用封禁(
blocked_end_users),他就拿不到新令牌。
来源白名单
嵌入策略里的 allowed_origins 限定哪些页面来源可以使用令牌。签发令牌时可以再收窄(传 allowed_origins,必须是策略白名单的子集)。来源不在名单上时,请求返回 EMBED_ORIGIN_NOT_ALLOWED(403)。
- 只接受
https来源;https://*.example.com形式的通配只匹配一级子域名,不含端口。 - 本地开发才打开
allow_localhost,上线前关掉。 - 来源由浏览器写入请求,它挡住的是别的网站拿你的令牌去用,挡不住拿到令牌的非浏览器客户端。令牌本身仍要妥善保管。
哪些不是秘密
下面这些内容,模型可能被用户要求复述,请当作公开信息对待:
- 智能体的指令(Console 里写的 instructions)。
- 覆盖指令(
agent_override.system)。 system.message里的宿主上下文。- 页面上下文和前端工具的返回值。
- 工具的名字、描述和输入结构。
所以不要在这些地方放密钥、内部规则、不想让用户看到的话术或别人的数据。需要保密的数据放在你的工具服务端,用终端用户身份控制谁能取到。
提示注入与不可信上下文
智能体读到的内容里,凡是来自浏览器或第三方的,都可能含有试图操纵它的指令:用户输入、页面上下文、网页内容、工具返回的文本。
- 页面上下文是不可信的。服务端把它放进附在本轮用户消息末尾的
<page_context untrusted="true">块里,不进系统提示,也不延续到下一轮。值里的<、>、&和引号会被转义,不能伪造出新的标签。详见前端工具与页面上下文。 - 可信事实走
system.message。只有持有 API Key 的后端能写入它,终端用户令牌不能。 - 不要靠指令里的「不要……」守住边界。真正要禁止的事,在工具一侧不提供,或者在服务端拒绝。
- 智能体可以调用的工具越少越安全:只为这个场景开需要的工具,写入类工具保留
always_ask,并在服务端校验。
iframe 与 Hosted
iframe 页的 frame-ancestors 来自智能体的来源白名单;白名单为空时禁止所有网站嵌入。Hosted 是独立页面,使用 frame-ancestors 'none'。平台托管的 chat 页从自身可信来源请求 API;宿主来源由 iframe 策略和跨窗口通信校验。
使用一行加载器时,宿主 CSP 还需在 frame-src 放行 https://chat-develop.praxisusercontent.com。加载器同时校验跨窗口消息的来源和发送窗口。Hosted 凭证只能使用一次,见嵌入令牌。
Shadow DOM
<praxis-agent> 渲染在 open Shadow DOM 里:宿主页的样式不会漏进对话,对话的样式也不会影响宿主页。这是样式隔离,不是安全边界:open 的 Shadow DOM 可以被页面脚本读取,同一页面上的任何脚本都能访问对话内容。不要把智能体嵌入你不信任的第三方脚本也在运行的页面里,需要强隔离时使用 iframe。
内容安全策略(CSP)
如果你的页面设置了 CSP,需要放行 Kit 脚本所在的来源,以及 Kit 连接 API 的来源。
| 环境 | 脚本来源(script-src) | 连接来源(connect-src) |
|---|---|---|
| develop | https://kit-develop.praxisusercontent.com | https://api-develop.deepraxis.com |
| 生产 | https://kit.praxisusercontent.com | https://api.deepraxis.com |
Content-Security-Policy:
default-src 'self';
script-src 'self' https://kit-develop.praxisusercontent.com;
connect-src 'self' https://api-develop.deepraxis.com;
frame-src https://chat-develop.praxisusercontent.com;要点:
connect-src里的 API 地址要和setOptions的api.url一致,也就是签发令牌的那个环境。- 如果你自己托管 Kit 的构建(如快速开始里的
/praxis-kit.js),script-src 'self'就够了,不需要放行 CDN。 - Kit 会向 Shadow DOM 里插入
<style>元素(用于主题)。设置了严格style-src的页面,需要允许内联样式,例如style-src 'self' 'unsafe-inline'。 - 头像、启动图片等你通过选项传入的图片地址,要放行
img-src。 - 宿主页面被别人嵌入的保护由宿主自己的
frame-ancestors决定。
子资源完整性(SRI)
从 CDN 加载时,用不可变路径并加上 integrity,浏览器会校验文件内容,CDN 被篡改时拒绝执行:
<script
type="module"
src="https://kit-develop.praxisusercontent.com/v0.1.0/praxis-kit.js"
integrity="sha384-…"
crossorigin="anonymous"
></script>integrity的值(sha384-…)由发布 Kit 版本时给出,路径里的版本号(v0.1.0)对应一次不可变的发布,内容不会改变。- 必须带
crossorigin="anonymous",否则浏览器不会校验。 - 浮动路径
https://kit-develop.praxisusercontent.com/v1/praxis-kit.js会随新版本更新内容,不要配integrity,配了会在下次发布后加载失败。需要锁定内容时请用不可变路径。
上线前检查清单
- API Key 只在后端,页面和仓库里找不到。
-
external_user_id来自你的登录态。 -
allowed_origins只有你的站点,生产环境没有开allow_localhost。 - 令牌有效期合理,登出时撤销令牌。
- 指令和
system.message里没有秘密。 - 工具服务端按
X-Praxis-External-User-Id鉴权,并认证调用方。 - 页面 CSP 放行了 Kit 与 API,CDN 加载使用不可变路径和 SRI。