CI / Build / Vet / Test (push) Canceled after 0s
首个提交。webproxy 是部署在服务器上的 Web 正向代理:打开网页输入任意 URL,由服务器代为请求目标站点,经 HTML/CSS 重写、静态资源代理、 重定向/Cookie/表单处理后回填浏览器,核心场景是经服务器访问其所在 内网的客户网站。 - 开源件:MIT LICENSE、根级 SECURITY.md、CONTRIBUTING.md、 CHANGELOG.md、Makefile、CI(gofmt/vet/build/test) - 安全止损:.gitignore 排除 debug.log(含内网 IP)/二进制/调试散文件/ 本地 config.json;config.example.json 默认 blacklist,不关 SSRF - module 路径规范化为 github.com/yexuejc/webproxy - 测试:新增 proxy_test.go(URL 编解码/子域解析/SSRF 分类/Origin 改写); tests/cookietest 手工 E2E 程序加 build tag 并拆为独立子包,不污染 go test ./... - 注释:全部 Go 源码按函数作用/场景/入参/出参 + 分支 + 变量标准补齐 - 清理:删除旧"浏览器持有 Cookie"方案弃用代码(rewriteSetCookie/ stripDomainSecure/reCookieDomain/reCookieSecure);会话 Cookie 改由 服务端按 origin 的 jar 持有,绕开跨站 iframe 的 SameSite 扣发
4.7 KiB
4.7 KiB
安全说明
1. 威胁模型(按危害排序)
| # | 威胁 | 说明 | 现状 |
|---|---|---|---|
| 1 | 开放代理被滥用 | 无鉴权暴露公网 → 被扫到当成免费代理/跳板,耗流量、引溯源投诉 | 未防护(鉴权未实现,见第 3 节加固项) |
| 2 | SSRF(服务端请求伪造) | 攻击者借你的服务器打内网/云元数据 169.254.169.254/127.0.0.1 管理口/file:// 等 |
默认防护,三档可配(见第 2 节) |
| 3 | 同源 XSS | 被代理页面与 UI 同源(iframe 无 sandbox),恶意站点 JS 可触达父窗口/cookie(sid 已 HttpOnly) |
部分防护,缓解项见第 3 节 |
| 4 | 会话 grow | sessions 无 TTL,长期运行缓慢增长 |
已知,重启即清(规划 TTL 清理) |
| 5 | 上游证书风险 | 目标 HTTPS 证书默认校验;insecure_skip_verify 打开后中间人可解密内网流量 |
由配置项控制,公网目标不建议开 |
2. 已实现的防护
| 防护 | 实现 |
|---|---|
| 协议白/黑名单 | 默认仅 http/https;blacklist 档禁用 file/gopher/ftp/ftps/dict/tftp/ldap/sftp |
| IP 分类拦截 | 默认拦 127/8、::1(loopback)、169.254/16(link-local,含云元数据);可选 block_private、block_reserved |
| 附加黑名单 | denied_ips CIDR 列表,逐 IP 命中即拒 |
| 白名单模式 | whitelist 档仅放行 allowed_ips / allowed_domains(精确+子域) |
| DNS 重绑定防护 | 先 LookupIP 校验、再用校验过的 IP pin 连接,消除 TOCTOU 窗口 |
| 自引用防护 | 目标 Host == 代理 Host 直接 400,防 /p/ 咬尾 |
| 会话隔离 | sid Cookie(HttpOnly,Path=/)→ 独立 CookieJar,多使用者登录态不串 |
| 响应头清洗 | 剥离上游 X-Frame-Options/CSP/COOP(iframe 嵌入与 JS 注入所需)、Content-Length(重写后长度必变)、Location(统一改写) |
| TLS 加固 | 上游 TLS 最低 1.2 |
SSRF 分档与场景配置的完整说明见 CONFIG.md 第 2 节。
3. 上线前加固清单
3.1 入口鉴权(最高优先级)
当前没有任何登录机制。公网暴露前,任选其一:
- 反代 Basic Auth(最省事):nginx/Traefik/Caddy 前置,认证通过才转发到 8765;
- VPN/零信任:只通过 Tailscale/WireGuard/企业 VPN 访问,代理只听内网
listen; - 后续版本计划内置账号登录(当前未实现,别依赖)。
反代示例(nginx,同时解决 HTTPS 和 Basic Auth):
server {
listen 443 ssl;
server_name proxy.example.com;
ssl_certificate /etc/nginx/cert.pem;
ssl_certificate_key /etc/nginx/key.pem;
auth_basic "webproxy";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:8765;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # 如后续启用 WS
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
}
}
3.2 SSRF 策略收紧建议
| 上线形态 | 建议 |
|---|---|
| 专用服务器、网络平面干净 | mode: "off" 可接受;仍建议 denied_ips 写上同机管理网段 |
| 共享服务器/VM | mode: "blacklist"(默认)+ block_private: true,私网按站点放开 denied_ips 的补集用白名单补 |
| 公网多人可用 | mode: "whitelist" + 入口鉴权,双闸门 |
3.3 同源 XSS 缓解(可选,有取舍)
给 UI 的 iframe 加 sandbox="allow-scripts allow-forms allow-popups"(不加 allow-same-origin)可让被代理页面跑在独立源,父窗口不再可触达。代价:沙箱源不带 sid Cookie,登录态隔离会失效,需等服务端改为按 iframe 参数/子域传会话再启用。单机自用、且不访问不可信站点时可维持现状。
3.4 运维面
- 只暴露必要端口,安全组做源 IP 限制更佳;
docker logs/systemd journal 定期巡检 403 记录(403 的突增=有人在扫你的代理);- 升级/改配置前备份
config.json,保留可回退版本。
4. 残留风险如实说明
- 无鉴权 = 无访问控制:在补上 3.1 之前,任何能访问到端口的人都能使用该代理,请勿直接公网裸奔;
- 黑名单是"默认放行"语义:blacklist 档放行未列出的一切目标,它防的是"经典被打点",不是"最小权限";要最小权限用 whitelist;
- 同源面:见 3.3,未启用 sandbox 前,请只把不可信站点的问题留在"知情"层面;
- 性能/资源:默认纯 Go 转发开销极低,无已知拒绝服务放大点(无全量缓存),但 HTML/CSS 走内存,超大页面有内存压力(规划流式)。