我们有些应用程序有时会进入不良状态,但只能在生产中使用(当然!)。尽管进行堆转储可以帮助收集状态信息,但使用远程调试器通常更容易。设置起来很容易-只需将其添加到他的命令行中:
-Xdebug -Xrunjdwp:transport = dt_socket,server = y,suspend = n,address = PORT
似乎没有可用的安全机制,因此在生产中打开调试将有效地允许任意代码执行(通过hotswap)。
我们混合使用在Solaris 9和Linux(Redhat Enterprise 4)上运行的1.4.2和1.5 Sun JVM。我们如何启用安全调试?还有其他方法可以实现我们的生产服务器检查目标吗?
更新:对于JDK 1.5+ JVM,可以指定调试器应绑定(bind)到的接口(interface)和端口。因此,如果在服务器上正确设置了SSH,KarlP的建议是绑定(bind)回送并仅使用SSH隧道连接到本地开发人员。
但是,似乎JDK1.4x不允许为调试端口指定接口(interface)。因此,我们可以在网络中某个位置阻止对调试端口的访问,也可以在OS本身中进行某些系统特定的阻止(如Jared建议的IPChains等)?
更新#2:这是一种黑客,即使在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,该Servlet具有适当的安全性,可以允许我们打开调试器。当然,以后不能将其关闭,并且调试器在打开后仍会混杂地监听。但是,这些是我们愿意接受的限制,因为对生产系统的调试将始终导致事后重启。
更新#3:我最终编写了三个类:(1)TurnOnDebuggerException,一个普通的'ol Java异常,(2)DebuggerPoller,一个后台线程检查文件系统上是否存在指定文件,以及(3)DebuggerMainWrapper,一个启动轮询线程,然后反射地调用另一个指定类的main方法的类。
这是它的用法:
现在,当您启动JVM时,除了启动后台轮询器线程外,其他所有内容都相同。假设该文件(我们称为TurnOnDebugger)最初不存在,则轮询器每N秒检查一次。当轮询器第一次注意到它时,它将抛出并立即捕获TurnOnDebuggerException。然后,代理开始。
您无法将其关闭,并且机器在打开时也不是很安全。从好的方面来说,我认为调试器不允许同时进行多个连接,因此维护调试连接是您的最佳防御方法。我们之所以选择文件通知方法,是因为它允许我们通过在目录中指定触发文件来piggy带我们现有的Unix身份验证/作者,在该目录中,只有适当的使用才有权。您可以轻松构建一个小的 war 文件,该文件通过套接字连接实现相同的目的。当然,由于无法关闭调试器,因此仅在杀死有问题的应用程序之前使用它来收集数据。如果有人需要此代码,请告诉我。但是,您只需花费几分钟即可将其自己放在一起。
最佳答案
如果使用SSH,则可以允许建立 channel 并将 channel 建立到本地主机。无需开发,全部使用sshd,ssh和/或腻子完成。
可以在本地接口(interface)127.0.0.1上设置Java服务器上的调试套接字。
关于java - 生产JVM的安全调试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/922779/