生产JVM的安全调试

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

-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不允许为调试端口指定接口。 那么,我们可以阻止访问网络中的某个调试端口,或者在操作系统本身中进行一些特定于系统的阻塞(如Dared建议的那样,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可以是任何保证不被抛出的exception。

我在Windows机器上对此进行了测试,以certificate(1)调试器端口最初没有接收到连接,并且(2)抛出如上所示的TurnOnDebuggerexception会导致调试器生效。 启动参数是必需的(至少在JDK1.4.2上),但是JVM正好处理了垃圾值。

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

更新#3:我最后编写了三个类:(1)TurnOnDebuggerException,一个简单的’ol Javaexception,(2)DebuggerPoller,一个后台线程检查文件系统上是否存在指定文件,以及(3)DebuggerMainWrapper,一个类,它启动轮询线程,然后reflection性地调用另一个指定类的main方法。

这是它的用法:

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

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

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

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

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

你是绝对正确的:Java调试API本质上是不安全的。 但是,您可以将其限制为UNIX域套接字,并使用SSL / SSH编写代理,以便您具有经过身份validation和加密的外部连接,然后将这些外部连接代理到UNIX域套接字中。 这至少可以减少您对可以进入服务器的人或可能破解SSL的人的暴露。

将信息/服务导出到JMX,然后使用RMI + SSL远程访问它。 您的情况就是JMX的设计目标(M代表管理)。

好问题。

我不知道加密到调试端口的连接的任何内置function。

可能有更好/更容易的解决方案,但我会做以下事情:

  1. 将生产机器置于阻止访问调试端口的防火墙后面。
  2. 在连接到端口的主机上运行代理进程,并加密套接字的输入和输出。
  3. 在调试工作站上运行代理客户端,该客户端也加密/解密输入。 将此连接到服务器代理。 它们之间的通信将被加密。
  4. 将调试器连接到代理客户端。