唯一安全的JVM调试绑定方式是address=127.0.0.1:5005,因其仅响应本机回环连接;SSH隧道必须用ssh -L 5005:localhost:5005确保逻辑地址对齐;VSCode中hostName必须设为localhost,且需用nc或telnet验证隧道连通性。

只绑定127.0.0.1,别用0.0.0.0或localhost
OpenJDK 的 JDWP 调试协议本身不带认证和加密,address=0.0.0.0:5005 或 address=*:5005 等同于把调试后门直接暴露在公网。攻击者只要知道 IP 和端口,就能 attach 进程、执行任意代码、dump 内存——这不是“可能被利用”,而是“必然被利用”。
正确做法是强制 JVM 只监听回环地址:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:5005- 不要用
localhost替代127.0.0.1:某些 JVM 版本或容器环境会将localhost解析为 IPv6 地址::1,导致监听失败或行为不一致 - 端口号可自定义(如
5006),但必须与后续 SSH 隧道、VSCode 配置严格一致
容器里也要写127.0.0.1,别映射调试端口
如果 Java 应用跑在 Docker 容器中,JVM 启动参数仍需写 address=127.0.0.1:5005;此时容器启动时不要加 -p 5005:5005。
原因很直接:JVM 只响应容器内部的 127.0.0.1:5005,宿主机或外部根本无法直连。一旦你映射了该端口,等于主动把本应隔离的调试入口捅穿了一层。
常见错误操作:
- 在
Dockerfile或docker run中暴露EXPOSE 5005或-p 5005:5005 - 在 Kubernetes Pod 中配置
containerPort: 5005并暴露 Service - 使用
hostNetwork: true模式运行调试容器
SSH 隧道必须用 localhost:localhost 对齐
远程调试必须依赖 SSH 隧道,而隧道命令写错就等于白设。关键不是“端口通不通”,而是“连接发起方的逻辑地址是否匹配 JVM 监听地址”。
正确命令是:
ssh -L 5005:localhost:5005 user@remote-server- 这表示:本地发往
localhost:5005的流量,经 SSH 加密后,在远程服务器上以“从 localhost 发起”的身份访问目标端口
常见错误写法及后果:
-
ssh -L 5005:remote-ip:5005→ 远程端尝试从网卡 IP 去连5005,但 JVM 只听127.0.0.1,请求根本收不到 -
ssh -R 5005:localhost:5005(反向隧道)→ 本地没监听,VSCode 连不上 - 隧道断开后不自动重连 → 生产调试建议用
autossh或 systemd service 管理,别靠前台终端维持
VSCode launch.json 的 hostName 必须是 localhost
launch.json 中的 hostName 字段不是填远程服务器 IP,它是告诉 VSCode:“去哪个地址连调试端口”。既然你用了 SSH 隧道,那目标就是本地监听的端口,所以必须是 localhost 或 127.0.0.1。
填错的后果不是“连不上”,而是 VSCode 绕过隧道,直接走公网尝试连接 remote-ip:5005——这既失败(防火墙/安全组拦截),又危险(暴露调试入口)。
示例正确配置片段:
{
"type": "java",
"name": "Attach to Remote",
"request": "attach",
"hostName": "localhost",
"port": 5005
}
注意:hostName 和 port 必须与 SSH 隧道本地端口完全一致;若隧道是 ssh -L 5006:localhost:5005,这里就得写 "port": 5006。
最容易被忽略的一点:JDWP 不提供任何访问控制机制,它信任所有能连上的客户端。所谓“安全”,全靠网络层隔离——绑定 127.0.0.1、用 SSH 隧道、禁用公网路由,三者缺一不可。

















