-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=PORT
似乎没有可用的安全机制,因此在生产环境中开启调试将有效地允许任意代码执行(通过热交换)。
我们有一组运行在Solaris 9和Linux(Redhat Enterprise 4)上的1.4.2和1.5 Sun JVM的混合体。如何启用安全调试?还有其他实现生产服务器检查的方法吗?
更新:对于JDK 1.5+ JVM,可以指定调试器应绑定到的接口和端口。因此,KarlP建议将其绑定到回环并只使用SSH隧道连接到本地开发者桌面,如果服务器上正确设置了SSH,则应该可以工作。
然而,似乎JDK1.4x不允许为调试端口指定接口。因此,我们可以在网络中某个地方阻止对调试端口的访问,或在操作系统本身中进行一些特定于系统的阻止(如Jared所建议的IPChains)?
更新#2:这是一个hack,即使在1.4.2 JVM上也可以限制我们的风险:
-Xdebug
-Xrunjdwp:
transport=dt_socket,
server=y,
suspend=n,
address=9001,
onthrow=com.whatever.TurnOnDebuggerException,
launch=nothing
打开Java调试器的代码:
try {
throw new TurnOnDebuggerException();
} catch (TurnOnDebugger td) {
//Nothing
}
TurnOnDebuggerException是一个保证不会在其他任何地方引发的异常。
我在Windows系统上测试过,证明了(1)调试器端口最初不接收连接,以及(2)按照上面的方式抛出TurnOnDebugger异常会使调试器启动。至少在JDK1.4.2上需要启动参数,但JVM可以优雅地处理垃圾值。
我们计划制作一个小servlet,通过适当的安全措施,让我们能够打开调试器。当然,一旦打开就无法关闭,而且调试器仍然会一直监听。但这些都是我们愿意接受的限制,因为对生产系统进行调试总是会导致重启。
更新#3: 我编写了三个类:(1)TurnOnDebuggerException,一个普通的Java异常,(2)DebuggerPoller,一个检查文件系统上指定文件存在性的后台线程,和(3)DebuggerMainWrapper,一个类,它启动轮询线程并反射调用另一个指定类的main方法。
用法如下:
- 在启动脚本中用DebuggerMainWrapper替换你的"main"类
- 添加两个系统 (-D) 参数,一个指定真正的主类,另一个指定文件系统上的文件。
- 在命令行上配置调试器,添加onthrow=com.whatever.TurnOnDebuggerException部分
- 将包含上述三个类的jar添加到classpath中。
现在,当你启动JVM时,除了启动一个后台轮询线程外,其余都是相同的。假设文件(我们的文件名为TurnOnDebugger)最初不存在,则轮询器每隔N秒检查一次。当轮询器首次注意到它时,它抛出并立即捕获TurnOnDebuggerException。然后,代理启动。
你无法再将其关闭,并且当其处于打开状态时,机器并不是非常安全。好处是,我认为调试器不允许多个同时连接,因此维护调试连接是您最好的防御。我们选择文件通知方法,因为它允许我们通过指定目录中的触发文件来依附于我们现有的Unix身份验证/授权。您可以轻松地构建一个小型war文件,通过套接字连接实现相同的目的。当然,由于我们无法关闭调试器,所以只会在关闭病态应用程序之前使用它来收集数据。如果有人需要这段代码,请告诉我。不过,自己编写这些代码只需要几分钟时间。