ciphera-net/sigil

GitHub: ciphera-net/sigil

一个自托管的 favicon 解析与标准化服务,替代第三方图标代理以防止用户查询域名泄露,并内置了严格的 SSRF 防护机制。

Stars: 1 | Forks: 0

# Sigil 一个小巧的自托管 favicon 解析器。给定一个域名,Sigil 会在**服务端**获取该站点的真实 favicon,将其标准化为您指定大小的 PNG,并缓存结果。它的存在是为了替代第三方 favicon 代理(例如 `google.com/s2/favicons`),从而确保解析图标的行为绝不会将您的用户所查询的域名泄露给外部第三方。 ## 安全模型 Sigil 作为一个独立服务存在的核心理由就是隔离:获取受攻击者影响的 URL 的代码,绝不能运行在持有数据库凭证或处于内部网络位置的进程中。正在运行的实例被设计为具有**零内部机密**且仅为**仅出站**访问权限——如果其防御机制被绕过,爆炸半径也仅限于一个只能与公共互联网通信的机器。 获取边界(`pkg/favicon/fetch.go`)针对每个请求以及**每一次重定向跳转**强制执行以下操作: - **拨号时 IP 验证(TOCTOU 安全)。** 解析出的 IP 会在 `net.Dialer.Control` 中进行检查——在 DNS 解析之后、连接之前,对每个候选地址立即执行一次——使用 [`code.dny.dev/ssrf`](https://code.dny.dev/ssrf)(一个基于 IANA 注册表衍生的拒绝列表)。这关闭了“先解析后连接”的漏洞,并防御了 DNS 重绑定:一个在检查和拨号之间发生重绑定的名称,依然会在拨号时被验证。验证是基于 `netip.Addr` 进行的,因此 IPv4 映射的 IPv6(`::ffff:169.254.169.254`)无法伪装成全局单播地址而蒙混过关。 - **默认拒绝的地址策略。** 环回地址、RFC 1918 私有地址空间、CGNAT(`100.64.0.0/10`)、链路本地 `169.254.0.0/16`(云元数据端点)、多播、保留地址范围、IPv6 ULA/链路本地地址以及 NAT64 全部被拒绝。仅允许 TCP 连接到 80/443 端口。 - **有界重定向。** 最多允许 3 次跳转,且每次跳转必须是 `http`/`https` —— `file://`、`gopher://` 等重定向会被拒绝。 - **有界响应。** 响应体会受到硬性字节上限的读取限制,内容类型由**内容嗅探**决定(绝不依赖响应头),仅接受光栅图像类型,并且在完全解码*之前*对解码后的像素尺寸进行边界限制,以防御解压缩炸弹。 - **仅通过沙盒化光栅化器处理 SVG。** SVG 是一种 XML,可能携带脚本(存储型 XSS 风险)或外部实体(XXE / 二次 SSRF),因此 SVG 字节永远不会被直接提供或存储:结构化检测到的 SVG 会受到边界限制(字节数、XML token、嵌套深度),并由纯 Go 渲染器([`oksvg`](https://github.com/srwiley/oksvg) + [`rasterx`](https://github.com/srwiley/rasterx))渲染为固定大小的像素缓冲区。该渲染器基于 `encoding/xml` 构建,没有任何加载外部实体、DTD 或 URL 的代码路径——从根本上无法表达 XXE 这类漏洞,并且无网络回归测试确保其始终保持这一特性。渲染器 panic 会被限制在每个候选地址的独立处理中。其输出与 Sigil 提供的每一个图标一样,都是全新编码的 PNG。 SSRF 测试套件(`pkg/favicon/fetch_test.go`)独立于防护库断言上述每一项策略,因此,即使依赖项升级导致某个范围发生回退,也会使我们的测试失败,而不会悄无声息地发布带漏洞的版本。 ## 它是什么(以及不是什么) - **是:** 一个经过强化的 favicon 获取器 + 标准化工具,可用作 Go 库(`github.com/ciphera-net/sigil/pkg/favicon`)或微型 HTTP 服务(`cmd/server`)。 - **不是:** 面向互联网的公共 favicon API、通用 URL 获取器或代理。已发布的实例保持内部使用;开源*代码*本身就是开源行为。 ## 安装(库) ``` go get github.com/ciphera-net/sigil/pkg/favicon ``` 需要 **Go 1.25+**。 ## API(服务) | 路由 | 响应 | |-------|----------| | `GET /icon?domain=&sz=<16\|32\|64\|128>` | `200 image/png` 解析出的图标 · `404` 无图标(已进行否定缓存) · `400` 域名/尺寸错误 · `502` 上游获取失败(未缓存) | | `GET /healthz` | 存活探针 | | `GET /metrics` | Prometheus | `domain` 必须是纯主机名(无协议、端口、路径或 IP 字面量)。 ## 自托管 ``` docker build -t sigil . docker run -p 8085:8085 sigil ``` 该容器是一个仅包含服务器二进制文件的 distroless 静态镜像。 ## CI `.woodpecker/` 作为独立的检查运行:`test`(包含 `gofmt`、`go vet`、`go test -race` 以及 SSRF 测试套件)、`govulncheck`(依赖漏洞扫描),以及——在服务落地后——`build` / `push` / `deploy`。
标签:EVTX分析, Go, Ruby工具, SSRF防御, Web工具, 图标解析, 日志审计, 网络安全, 自定义请求头, 自托管服务, 请求拦截, 隐私保护