敏感数据与出站请求
插件连接第三方服务时,需要同时保护认证信息和 Halo 所在网络。用户能够填写一个 URL,不代表插件可以直接从服务端访问该地址,更不能在校验地址前附加 Token。
使用 Secret 保存敏感数据
密码、Token、API Key 和私钥应保存在 Halo Secret 中。Setting、ConfigMap、自定义模型 spec 和 UI 状态只保存 Secret 的名称,不保存或返回密钥明文。
Setting 表单可以使用 secret 输入组件:
服务端通过 ReactiveExtensionClient 获取 Secret,并按插件约定的键读取值:
不要把 Secret 内容写入日志、异常消息、资源状态、公开 API 或返回给 Console 的普通查询接口。提供查看权限的 RoleTemplate 也不应因此获得密钥读取能力。
secret 输入组件从 Halo 2.25.0 开始支持 descriptionPreset,其他参数及版本参考表单定义。
限制出站目标
第三方 API 地址固定时,应在代码中使用固定 HTTPS 地址,不提供自定义基础 URL。确实需要支持私有部署或多个服务地址时,至少执行以下检查:
- 使用 URI 解析器处理地址,只允许业务需要的协议、主机和端口,禁止用户名、密码和不受支持的 URI 结构。
- 优先使用明确的域名允许列表。仅依赖字符串前缀、正则表达式或 URL 后缀判断不足以防止绕过。
- 解析目标的全部 IPv4 和 IPv6 地址,拒绝环回、私网、链路本地、组播、未指定地址和云平台元数据地址。
- 禁止自动跟随重定向,或对每一次重定向重新执行同样的目标检查。
- 目标确认安全之后再添加 Authorization、Cookie 或其他凭据;不要在可能跳转到其他主机的客户端上配置全局认证头。
- 为连接、响应和整体请求设置超时,并限制响应体大小,避免出站请求长期占用事件循环、连接或内存。
DNS 结果可能变化,允许用户输入任意域名时还需要考虑 DNS rebinding。能使用固定地址或受控允许列表时,不要实现一个通用代理。
Halo 服务端基于 Spring WebFlux。出站 HTTP 请求应使用响应式 WebClient,不要在请求、过滤器、端点或 Reconciler 的响应式链路中调用阻塞客户端。
更多通用防护原则参考 OWASP SSRF Prevention Cheat Sheet。
对安全开关采用 fail closed
公开 API、匿名访问、远程同步等安全相关能力在配置缺失或读取失败时应保持关闭。不要通过 defaultIfEmpty(true) 或 onErrorReturn(true) 把异常变成开放状态。
读取错误应记录不包含敏感值的诊断信息,并返回关闭状态或明确失败;只有配置被成功读取且显式启用时,才开放相应能力。
发布前检查
- 资源和 ConfigMap 中没有密码、Token、API Key 或私钥明文。
- 读取普通业务资源的用户无法获得 Secret 内容。
- 所有用户可配置的出站地址都经过协议、主机、DNS 地址和重定向检查。
- 凭据只发送给完成校验的目标。
- WebClient 配置了超时和响应大小边界。
- 配置缺失、读取失败和远程服务异常不会意外开放 API 或权限。
- 日志、Toast 和 API 错误响应不包含凭据或完整敏感请求内容。