生产JVM的安全调试 [英] Secure Debugging for Production JVMs

查看:221
本文介绍了生产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,可以指定一个接口和端口调试器应该绑定。因此,KarlP建议将绑定到环回并且只需使用SSH隧道到本地开发人员框中即可,因为在服务器上正确设置了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

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,一个类启动轮询线程,然后反射地调用另一个指定类的主要方法。



这是它如何使用:


  1. 在您的启动脚本中使用DebuggerMainWrapper替换主类

  2. 添加两个系统(-D)参数,一个指定真正的主类,另一个在文件系统上指定一个文件。

  3. 在命令行上使用onthrow = com.whatever.TurnOnDebuggerException部分添加调试器

  4. 将上述三个类添加到类路径中。

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



您不能将其关闭,并且机器在启动时不是非常安全的。在上面,我不认为调试器允许多个并发连接,因此维护调试连接是您最好的防御。我们选择了文件通知方法,因为它允许我们通过在只有正确使用的权限的目录中指定触发器文件来搭载现有的Unix authen / author。您可以轻松地构建一个通过套接字连接实现相同目的的小型战争文件。当然,由于我们无法关闭调试器,所以我们只能在杀死病毒的应用程序之前收集数据。如果有人想要这个代码,请让我知道。但是,只需要几分钟的时间把它扔在一起。

解决方案

如果使用SSH,您可以允许隧道和将端口隧道连接到本地主机。不需要开发,所有这些都使用sshd,ssh和/或putty完成。



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


We have some applications that sometimes get into a bad state, but only in production (of course!). While taking a heap dump can help to gather state information, it's often easier to use a remote debugger. Setting this up is easy -- one need only add this to his command line:

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=PORT

There seems to be no available security mechanism, so turning on debugging in production would effectively allow arbitrary code execution (via hotswap).

We have a mix of 1.4.2 and 1.5 Sun JVMs running on Solaris 9 and Linux (Redhat Enterprise 4). How can we enable secure debugging? Any other ways to achieve our goal of production server inspection?

Update: For JDK 1.5+ JVMs, one can specify an interface and port to which the debugger should bind. So, KarlP's suggestion of binding to loopback and just using a SSH tunnel to a local developer box should work given SSH is set up properly on the servers.

However, it seems that JDK1.4x does not allow an interface to be specified for the debug port. So, we can either block access to the debug port somewhere in the network or do some system-specific blocking in the OS itself (IPChains as Jared suggested, etc.)?

Update #2: This is a hack that will let us limit our risk, even on 1.4.2 JVMs:

Command line params:

-Xdebug
-Xrunjdwp:
    transport=dt_socket,
    server=y,
    suspend=n,
    address=9001,
    onthrow=com.whatever.TurnOnDebuggerException,
    launch=nothing

Java Code to turn on debugger:

try {
    throw new TurnOnDebuggerException();
} catch (TurnOnDebugger td) {
   //Nothing
}

TurnOnDebuggerException can be any exception guaranteed not to be thrown anywhere else.

I tested this on a Windows box to prove that (1) the debugger port does not receive connections initially, and (2) throwing the TurnOnDebugger exception as shown above causes the debugger to come alive. The launch parameter was required (at least on JDK1.4.2), but a garbage value was handled gracefully by the JVM.

We're planning on making a small servlet that, behind appropriate security, can allow us to turn on the debugger. Of course, one can't turn it off afterward, and the debugger still listens promiscuously once its on. But, these are limitations we're willing to accept as debugging of a production system will always result in a restart afterward.

Update #3: I ended up writing three classes: (1) TurnOnDebuggerException, a plain 'ol Java exception, (2) DebuggerPoller, a background thread the checks for the existence of a specified file on the filesystem, and (3) DebuggerMainWrapper, a class that kicks off the polling thread and then reflectively calls the main method of another specified class.

This is how its used:

  1. Replace your "main" class with DebuggerMainWrapper in your start-up scripts
  2. Add two system (-D) params, one specifying the real main class, and the other specifying a file on the filesystem.
  3. Configure the debugger on the command line with the onthrow=com.whatever.TurnOnDebuggerException part added
  4. Add a jar with the three classes mentioned above to the classpath.

Now, when you start up your JVM everything is the same except that a background poller thread is started. Presuming that the file (ours is called TurnOnDebugger) doesn't initially exist, the poller checks for it every N seconds. When the poller first notices it, it throws and immediately catches the TurnOnDebuggerException. Then, the agent is kicked off.

You can't turn it back off, and the machine is not terribly secure when its on. On the upside, I don't think the debugger allows for multiple simultaneous connections, so maintaining a debugging connection is your best defense. We chose the file notification method because it allowed us to piggyback off of our existing Unix authen/author by specifying the trigger file in a directory where only the proper uses have rights. You could easily build a little war file that achieved the same purpose via a socket connection. Of course, since we can't turn off the debugger, we'll only use it to gather data before killing off a sick application. If anyone wants this code, please let me know. However, it will only take you a few minutes to throw it together yourself.

解决方案

If you use SSH you can allow tunneling and tunnel a port to your local host. No development required, all done using sshd, ssh and/or putty.

The debug socket on your java server can be set up on the local interface 127.0.0.1.

这篇关于生产JVM的安全调试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆