open-code-review Viewer 安全详解:DNS Rebinding防御与安全头加固指南
【免费下载链接】open-code-reviewFast, efficient, battle-tested at Alibaba's scale. Hybrid architecture code review tool: deterministic pipelines + LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, SQL injection), OpenAI & Anthropic compatible.项目地址: https://gitcode.com/GitHub_Trending/op/open-code-review
open-code-review(OCR)的Viewer是一个内嵌的 Web 会话查看器,用浏览器浏览历史代码审查记录。正因为它会把被审查的源代码和LLM 分析结果渲染到网页上,本地 Viewer 的安全设计格外关键。本文将从新手视角讲清楚:Viewer 是如何防御DNS Rebinding 攻击的,又设置了哪些安全响应头,让你可以安心地开启它。
为什么本地审查 Viewer 需要安全防御?
很多开发者直觉上认为:ocr viewer只监听本机端口,外人访问不到,自然安全。但现实中有个隐藏漏洞 🕳️:
- Viewer 展示的会话 JSONL 里,包含完整的 diff 源码和发给 LLM 的请求内容;
- 攻击者只需要让你打开他的一枚恶意网页,网页里的脚本就能悄悄向
127.0.0.1发起请求; - 由于请求来自你自己的浏览器,同源策略形同虚设——这就是经典的DNS Rebinding(DNS 重绑定)攻击。
官方文档中也明确说明了这一防护设计,见 pages/src/content/docs/en/viewer.md。
DNS Rebinding 攻击原理:攻击者页面如何"偷看"本地数据
攻击链其实很短:
- 攻击者注册域名
evil.com,让它的 DNS 记录指向127.0.0.1; - 你打开
evil.com,页面上的 JS 请求http://evil.com:5483/——浏览器按 DNS 解析,实际访问的是你本机的 Viewer; - 关键细节:此时 HTTP 请求的
Host头里写的是evil.com,而不是localhost; - 浏览器认为"同源",恶意脚本顺利读到会话内容。
防御的核心思路因此非常直接:在服务器端校验Host头,不认识的主机名一律拒绝✅
hostGuard:Host 头白名单的防御设计
实现位于 internal/viewer/hostguard.go,核心是一个hostGuard中间件,工作方式如下:
| 环节 | 做了什么 | 防住了什么 |
|---|---|---|
hostOnly解析 | 剥离端口、小写化、处理 IPv6 方括号;对带多个冒号的裸 IPv6 直接判为无效 | 各种畸形 Host 头绕过 |
| 回环地址放行 | localhost、127.0.0.0/8、::1永远允许 | 保证本机正常使用不受影响 |
| 白名单匹配 | 不在白名单 → 返回403 forbidden host | 拦截evil.com这类攻击者域名 |
白名单如何构建(buildAllowedHosts函数):
- 默认只含三个回环名:
localhost、127.0.0.1、::1; - 具体绑定地址自动加入:如果你执行
ocr viewer --addr 192.168.1.10:5483,这个 IP 会被自动放行,局域网同事可以访问; - 通配符绑定(
:3000、0.0.0.0、::)刻意不自动放行——这是有意为之:暴露到公网/局域网属于高风险操作,强制你通过环境变量OCR_VIEWER_ALLOWED_HOSTS(逗号分隔主机名)显式声明允许哪些主机,等于逼你"确认风险"后才生效。
对应测试用例覆盖了典型攻击场景,见 internal/viewer/hostguard_test.go:攻击者域名、带端口的伪造、169.254.169.254元数据地址、公网 IP 重绑定,全部被 403 拦截。
安全响应头:每一层都在补位
除了 Host 校验,Viewer 还对每个响应叠加一层防御纵深头,实现在 internal/viewer/securityheaders.go:
| 响应头 | 取值 | 作用 |
|---|---|---|
Content-Security-Policy | default-src 'self'; script-src 'self'; ... | 只允许加载本站资源,且不含unsafe-inline——即使某段用户/LLM 内容突破了模板转义,也无法注入脚本 |
X-Content-Type-Options | nosniff | 禁止浏览器"猜测"MIME 类型 |
X-Frame-Options | DENY | 禁止页面被 iframe 嵌套,防点击劫持 |
Referrer-Policy | no-referrer | 绝不向外泄露来源地址 |
Permissions-Policy | 禁用地理位置/摄像头/麦克风 | 关闭与审查业务无关的浏览器权限 |
💡 一个值得学习的细节:HSTS 被刻意省略。因为 Viewer 只在回环地址上提供纯 HTTP,HSTS 在此毫无意义,反而会错误地把浏览器"钉"在 localhost 上——代码注释里写明了这个取舍,见 internal/viewer/securityheaders.go#L23-L27。
中间件挂载顺序与快速上手建议
在 internal/viewer/server.go#L53-L61 中,两层防御的嵌套顺序是:
securityHeaders( hostGuard( 路由 ) )即先过 Host 白名单,再过安全头,攻击请求在入口就被挡下。
给新手的三条实践建议 📌:
- 默认用法最安全:直接
ocr viewer,绑定localhost:5483,白名单天然收敛; - 局域网共享:用具体 IP 绑定(
--addr 192.168.x.x:5483),该地址自动放行; - 通配符绑定:务必设置
OCR_VIEWER_ALLOWED_HOSTS=box.local,192.168.1.10,否则局域网内其他主机访问会收到 403。
总结
open-code-review 的 Viewer 用一套小而精的设计,守住了本地审查数据的边界:
- hostGuard以默认拒绝的 Host 白名单,把 DNS Rebinding 攻击挡在门外,并用"通配符绑定不自动放行"的设计强制使用者确认风险;
- securityHeaders叠加 CSP、防点击劫持、权限最小化等响应头,形成多层防线;
- 每一处取舍(比如不加 HSTS)都有清晰注释说明理由——这正是新手学习 Web 安全设计的好范本 📚
<output文章结束> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章> </输出文章>
【免费下载链接】open-code-reviewFast, efficient, battle-tested at Alibaba's scale. Hybrid architecture code review tool: deterministic pipelines + LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, SQL injection), OpenAI & Anthropic compatible.项目地址: https://gitcode.com/GitHub_Trending/op/open-code-review
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考