生产JVM的安全调试

Sha*_*Doo 18 java security debugging

我们有一些应用程序有时会陷入糟糕的状态,但仅限于生产(当然!).虽然进行堆转储可以帮助收集状态信息,但使用远程调试器通常更容易.设置它很容易 - 只需将其添加到他的命令行:

-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,可以指定调试器应绑定的接口和端口.因此,如果在服务器上正确设置了SSH,KarlP建议绑定到环回并仅使用SSH隧道连接到本地开发人员框.

但是,似乎JDK1.4x不允许为调试端口指定接口.那么,我们可以阻止访问网络中某个地方的调试端口,或者在操作系统本身中进行一些特定于系统的阻塞(如Jared建议的那样,IPChains等)?

更新#2:这是一个让我们限制风险的黑客,即使在1.4.2 JVM上也是如此:

命令行参数:

-Xdebug
-Xrunjdwp:
    transport=dt_socket,
    server=y,
    suspend=n,
    address=9001,
    onthrow=com.whatever.TurnOnDebuggerException,
    launch=nothing
Run Code Online (Sandbox Code Playgroud)

用于打开调试器的Java代码:

try {
    throw new TurnOnDebuggerException();
} catch (TurnOnDebugger td) {
   //Nothing
}
Run Code Online (Sandbox Code Playgroud)

TurnOnDebuggerException可以是任何保证不被抛出的异常.

我在Windows机器上对此进行了测试,以证明(1)调试器端口最初没有接收到连接,并且(2)抛出如上所示的TurnOnDebugger异常导致调试器变为活跃状态.启动参数是必需的(至少在JDK1.4.2上),但是JVM正好处理了垃圾值.

我们计划制作一个小型servlet,在适当的安全性之后,可以允许我们打开调试器.当然,之后无法将其关闭,调试器一旦打开就仍然会混杂地监听.但是,这些是我们愿意接受的限制,因为生产系统的调试将始终导致重新启动.

更新#3:我最后写了三个类:(1)TurnOnDebuggerException,一个简单的'ol Java异常,(2)DebuggerPoller,一个后台线程检查文件系统上是否存在指定文件,以及(3)DebuggerMainWrapper,一个类启动轮询线程,然后反射调用另一个指定类的main方法.

这是它的用法:

  1. 在启动脚本中用DebuggerMainWrapper替换"main"类
  2. 添加两个系统(-D)参数,一个指定真正的主类,另一个指定文件系统上的文件.
  3. 使用onthrow = com.whatever.TurnOnDebuggerException部件在命令行上配置调试器
  4. 将包含上述三个类的jar添加到类路径中.

现在,当您启动JVM时,除了启动后台轮询器线程之外,所有内容都是相同的.假设文件(我们的名为TurnOnDebugger)最初不存在,轮询器每隔N秒检查一次.当轮询器首次注意到它时,它会抛出并立即捕获TurnOnDebuggerException.然后,代理人开始了.

您无法将其关闭,并且机器在打开时不是非常安全.从好的方面来说,我不认为调试器允许多个同时连接,因此保持调试连接是最好的防御.我们选择了文件通知方法,因为它允许我们通过在只有正确使用权限的目录中指定触发器文件来捎带我们现有的Unix authen/author.您可以轻松地构建一个通过套接字连接实现相同目的的war文件.当然,由于我们无法关闭调试器,因此我们只会在杀死病毒应用程序之前使用它来收集数据.如果有人想要这个代码,请告诉我.但是,您只需要几分钟就可以将它们放在一起.

Kar*_*rlP 8

如果使用SSH,则可以允许隧道连接并将端口隧道连接到本地主机.无需开发,全部使用sshd,ssh和/或putty完成.

可以在本地接口127.0.0.1上设置java服务器上的调试套接字.