vesvault/snif
GitHub: vesvault/snif
SNIF 通过基于 SNI 的端到端 TLS 转发,让 NAT 后的 IoT 设备无需公网 IP 即可获得公共可信的 HTTPS 主机名并直接终止 TLS。
Stars: 16 | Forks: 1
```
/**************************************************************************
* _________
* /````````_\ S N I F ~ e2e TLS trust for IoT
* /\ , / O\ ___
* | | | \__|_____/ o\ e2e TLS SNI Forwarder
* | | | ``/`````\___/ e2e TLS CA Proxy
* | | | . | <"""""""~~
* | \___/ `` \________/ https://snif.host
* \ ''' ``` /```````` (C) 2021-2026 VESvault Corp
* \_________/ Jim Zubov
*
*
* Apache License, Version 2.0
* You may use, copy, modify, merge, publish, distribute and/or sell copies
* of the Software under the terms of the Apache License, Version 2.0, a copy
* of which is provided in the COPYING file, or http://www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*
**************************************************************************/
```
# SNIF — 为 NAT 背后的设备提供端到端 TLS 信任
[](https://github.com/vesvault/snif/actions/workflows/build.yml)
[](https://github.com/vesvault/snif/actions/workflows/codeql.yml)
[](COPYING)
[](https://datatracker.ietf.org/doc/draft-zubov-snif/)
**SNIF 赋予任何设备上的任何应用一个公共的、浏览器信任的 HTTPS 主机名 ——
无需公共 IP,无需端口转发,也无需将你的私钥交给任何人。**
设备生成自己的 TLS 私钥,获取由 CA 签发的真实证书
用于 `*.snif.xyz` 主机名,并接受通过公共 SNIF 中继转发的
入站 TLS 连接。中继根据其 SNI 记录转发原始加密 TCP 流——
它绝不持有私钥,也无法读取或篡改
流量。其结果是一个点对点的、应用层面的 TLS 隧道,没有任何可读的中间人。
## 它解决的问题
IoT 设备、家庭服务器和移动应用通常位于 NAT 背后,没有
公共 IP 和稳定的 DNS 名称。常见的替代方案都放弃了
端到端信任:
- **端口转发 / 动态 DNS** —— 需要路由器访问权限,并且会直接
暴露设备。
- **反向代理隧道** —— 提供商会终止 TLS,因此它可以读取并
修改通过的所有内容。
- **VPN** —— 为每台设备进行配置非常繁琐,并且仍然需要信任一个集中器。
SNIF 将 TLS 终止保持在**设备上**。中继只能看到一个不透明的、
基于 SNI 路由的字节流,任何不当行为都可以通过
CA 证书记录被公开检测到。
## 工作原理
私钥由 SNIF connector 在本地生成,并且永远不会
离开设备。
connector 向 SNIF 中继上的 CA 代理发送 CSR。代理获取
X.509 证书并将其返回给设备。
有了证书和私钥,connector 就可以终止 TLS。
到达设备主机名的传入连接首先抵达中继,中继读取
SNI 记录以识别目标设备,并通过匹配的 connector 转发
TLS TCP 流。
设备可以将 `snifd` 作为一个独立的 connector 进程运行,将传入的
TLS 转发到本地端口——可以作为由 `snifd` 终止 TLS 的普通 TCP,或者由
监听应用使用共享的证书和密钥来终止 TLS。在
更高级的设置中,connector 直接集成到提供服务的应用程序中。
从客户端的角度来看,到 SNIF 主机名的 TLS 连接的
工作方式与连接到任何受信任的服务器完全一样。
为了避免通过公共 CA 日志暴露唯一的设备主机名,CA 代理
可以为子域签发泛域名证书;实际的主机名则是该子域中
一个特定的、未公开列出的主机。
### 初始化 TLS 证书
```
DNS: *.snif.xyz
| (no public IP or DNS hostname)
v
SNIF Relay IoT Device
+----------------+ +--------------------------------+
| | | Generate a Private Key |
| | | (never leaves the device) |
Certificate | snif-cert: | | |
Authority | <-----< Request a permanent hostname |
+---------+ | >-----> host1.snif.xyz |
| | | | | |
| CSR <-----< PKCS#10 CSR <-----< PKCS#10 CSR for host1.snif.xyz |
| Verify <-----> host1.snif.xyz | | |
| Issue >-----> X.509 cert >-----> X.509 cert for host1.snif.xyz |
| | | | | |
+---------+ +----------------+ +--------------------------------+
```
### 接受 TLS 连接
```
DNS: *.snif.xyz
| (no public IP or DNS hostname)
v
SNIF Relay IoT Device
+----------------+ +--------------------------------+
| | | Private Key + |
| | | X.509 cert for host1.snif.xyz |
| | | v v v v v |
| snifd relay: | | snifd connector or app: |
| | | |
| <-----< open ctl connection |
| TLS SNI= | | |
| host1.snif.xyz >-----> receive ctl notification |
+-------> ============== <-----< launch Server Process |
| | e2e TLS tunnel | | |
| | | | |
| +----------------+ +--------------------------------+
|
+-------^------------------+
| https://host1.snif.xyz |
| (TLS SNI=host1.snif.xyz) |
| |
| A web browser, or |
| any TLS enabled client, |
| anywhere on the Internet |
+--------------------------+
```
## 快速开始 — 在设备上运行 connector
```
./configure
make
sudo make install
```
检查 `/etc/snif/snif.conf` 并在需要时调整端口映射和其他
变量。该配置默认使用由
VESvault 运营的公共 SNIF 中继 —— 使用条款请参见 https://snif.host。
```
# 首次运行会打印一个 authorization link —— 打开它以授权 cert issuance
snif-conn
# 一旦授权,再次运行;它会打印出永久
# 分配给此 connector 的 SNIF hostname
snif-conn
```
然后启用守护进程(当 `/lib/systemd/system` 可用时,会自动安装一个 systemd 单元):
```
systemctl enable snif-conn
systemctl start snif-conn
```
将你的本地 TLS 服务指向 SNIF 证书和密钥 ——
`/etc/snif/snif.crt` 和 `/etc/snif/snif.key`。对于非 root 进程,请将
服务的 uid 添加到 `snif` 组中,以授予对这些文件的访问权限。
测试一下:假设 SNIF 端口 443 映射到了设备的 HTTPS 服务器,
从任何地方打开 `https://{snif_host_name}`。
## 将 connector 嵌入到应用中
要直接集成 SNIF 而不是运行 `snif-conn`:
- 使用 [`lib/cert.h`](lib/cert.h) 来分配 SNIF 主机名,生成
私钥,并签发和续订证书。
- 打开一个到 TCP 端口 `snif` (7123) 上的 `{snif_host_name}` 的 SNIF 控制连接。
- 使用 [`lib/conn.h`](lib/conn.h) 通过控制连接发送和接收 SNIF 消息,并管理服务连接。
connector 库编译为 `libsnif`。
## 运行私有 SNIF 中继
中继是一个独立的部署(connector + 中继 `snifd` 以及 CA
代理)。它不需要嵌入到任何其他内容中。设置说明请参见
[`ca-proxy/README`](ca-proxy/README)。
## 目录
```
lib/ SNIF connector libraries (libsnif) source
snifd/ SNIF daemon source — relay and connector
ca-proxy/ CA proxy scripts and web API
```
## 环境要求
**Connector (`snifd` + `snif-conn`)**
- OpenSSL >= 1.0.1
- cURL
**私有中继 (`snifd` + `snif-relay` + `ca-proxy`)**
- 带有 `.htaccess` 的 HTTP + HTTPS 服务器(已在 Apache 上测试)
- `mod_rewrite` 和 `mod_headers`(针对其他服务器调整 `.htaccess` 文件)
- PHP + `mod_php`
- Perl + CPAN
## 规范与安全性
SNIF 是一个规范的开源协议,已作为 IETF Internet-Draft 发布
[draft-zubov-snif](https://datatracker.ietf.org/doc/draft-zubov-snif/)
("Deploying Publicly Trusted TLS Servers on IoT Devices Using SNI-based
End-to-End TLS Forwarding")。其快照和平实语言的信任模型位于
[`doc/`](doc/):
- [doc/security-model.md](doc/security-model.md) — SNIF 保护的内容、信任
假设以及威胁模型。
- [doc/draft-zubov-snif-04.txt](doc/draft-zubov-snif-04.txt) — 内置的规范快照。
要报告漏洞,请参阅 [SECURITY.md](SECURITY.md) —— 请私下披露,
不要通过公开的 issues。
## 许可证
SNIF 采用 **Apache License, Version 2.0** 授权 —— 详见 [COPYING](COPYING)
和 [NOTICE](NOTICE)。connector 和中继均采用宽松的开源许可证:
您可以将 connector 嵌入到专有应用中,并建立您自己的中继,
而无需承担 copyleft 义务。
标签:SNI转发, TLS/SSL, 内网穿透, 安全合规, 安全测试工具, 客户端加密, 物联网, 网络代理