【问题标题】:How to configure JMX to bind to localhost only?如何将 JMX 配置为仅绑定到本地主机?
【发布时间】:2016-05-23 21:01:31
【问题描述】:

我在 Centos6 上使用 JDK8 运行 Tomcat8。 我使用以下选项启用 JMX:

CATALINA_OPTS="${CATALINA_OPTS} -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9123 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=true"

不幸的是,当我检查打开了哪些端口时,我发现这些端口监听所有 IP:

netstat -plunt | grep java
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 :::60555                            :::*                LISTEN      22752/java
tcp        0      0 ::ffff:127.0.0.1:8080               :::*                LISTEN      22752/java
tcp        0      0 :::9123                             :::*                LISTEN      22752/java
tcp        0      0 :::40867                            :::*                LISTEN      22752/java

我想如果我配置 -Dcom.sun.management.jmxremote.local.only=true 所有端口应该只绑定到本地主机(::ffff:127.0.0.1 将出现在所有端口之前)。

如何将 JMX 配置为仅绑定到本地主机?

已添加

我不创建 JMX 我使用 Tomcat JMX:https://tomcat.apache.org/tomcat-8.0-doc/monitoring.html

【问题讨论】:

  • 可能是 java.rmi.server.hostname (-Djava.rmi.server.hostname=127.0.0.1)?
  • 不是,结果是一样的

标签: java jmx


【解决方案1】:

你的要求是不必要的。

com.sun.management.jmxremote.local.only=true(顺便说一句,这已经是默认设置)意味着它只会接受来自本地主机的连接。这并不意味着它只会像您假设的那样绑定到环回接口。不接受来自不在本地主机上的连接只是另一种方式。从sun.management.jmxremote.LocalRMIServerSocketFactory 你可以看到它是这样完成的:

// Walk through the network interfaces to see
// if any of them matches the client's address.
// If true, then the client's address is local.
while (nis.hasMoreElements()) {
    NetworkInterface ni = nis.nextElement();
    Enumeration<InetAddress> addrs = ni.getInetAddresses();
    while (addrs.hasMoreElements()) {
        InetAddress localAddr = addrs.nextElement();
        if (localAddr.equals(remoteAddr)) {
            return socket;
        }
    }
}

我不知道为什么这样做而不是绑定到环回。但我相信它同样安全。 (或者可能不是?)

但如果你真的想要,那么由于 Java 8u102 和 Java 7u131 系统属性com.sun.management.jmxremote.host 将底层 RMI 注册表绑定到选定的网络接口。该值可以是InetAddress.getByName(String) 接受的任何字符串。

例子:

-Dcom.sun.management.jmxremote.host=localhost

请参阅:JDK-6425769 了解更多信息。

链接:Java 8u102 Release Notes

文档在任何地方都没有提到的是,即使设置了com.sun.management.jmxremote.host,您仍然会看到一个绑定到所有网络接口的 JMX 端口。这是因为如果 com.sun.management.jmxremote.local.only=true 则将启动 sun.management.jmxremote.LocalRMIServerSocketFactory 的实例,并且该实例不允许自定义,即它不尊重 com.sun.management.jmxremote.host 属性。如果这是一个错误、JDK-6425769 实现中的疏忽还是故意的,我不知道。

【讨论】:

  • 进行地址检查不一定像绑定到本地主机一样安全。如果您仅绑定到 localhost,那么无论如何,攻击者都无法与您交谈并说服您做一些您不应该做的事情。如果您接受网络连接,攻击者可能能够在远程地址检查发生之前利用某些漏洞。可能还有其他实现细节确实使它“同样安全”,但原则上,最好绑定到 localhost。
  • @DanPritts。我不同意。但是,我假设 JDK 开发人员必须有充分的理由这样做。
  • 当然,他们可能有充分的理由,例如,很难以“正确”的方式进行操作,因此他们改为这样做。或者他们可能根本没有充分的理由,也许是多年前人们对安全问题没有那么认真考虑的时候。最重要的是,除非有其他缓解因素,否则它并不“同样安全”。添加绑定到特定接口的功能表明没有,尽管我不知道这是事实。
  • 即使配置了local.only=true,我也能够成功地从另一台主机创建连接:tcp6 0 0 192.168.100.20:7091 192.168.100.34:54737 ESTABLISHED.20 是 RMX 主机,.34 是我的客户端。这不应该是可能的,不是吗?
  • 此外,通过设置-Dcom.sun.management.jmxremote.host=localhost 我真的只在 127.0.0.1 上看到一个 LISTENING 并且我无法像以前那样与我的客户建立联系。 tcp6 0 0 127.0.0.1:7091 :::* LISTEN 所以看起来事情同时发生了变化,我在 UB 16.04 LTS 服务器上使用 openjdk version "1.8.0_191"
【解决方案2】:

据我了解this 的回答并阅读了 Oracle 的文档,似乎有 no 方法可以在不编码的情况下对其进行配置。 This 在“连接器服务器属性”一章中说:

当使用默认的 JRMP 传输时,RMI 套接字工厂可以 使用属性jmx.remote.rmi.client.socket.factory 指定 和jmx.remote.rmi.server.socket.factory 在给定的环境中 RMIConnectorServer 构造函数。这些属性的值 必须是 RMIClientSocketFactoryRMIServerSocketFactory 类型, 分别。这些工厂在创建 RMI 对象时使用 与连接器相关联。

我看到的唯一选择是实现像here 这样的自定义工厂,并将类名与类路径中的 JAR/类一起传递给属性。

如果我错了,请纠正我。

【讨论】:

  • 我不创建JMX的问题我用Tomcat JMX:https://tomcat.apache.org/tomcat-8.0-doc/monitoring.html。所以,我想在这种情况下我无法将端口绑定到本地主机。对吗?
  • 我不这么认为。在我看来,您需要将自定义代码打包到 JAR 中,并可能将其与 bootstrap.jar 一起添加到引导类路径中。从简单而不是 Tomcat 开始,以消除测试开销。
  • 但我必须使用 Tomcat JMX :(
  • @Michael:你可能不明白。没有Tomcat JMX。 Tomcat 使用 VM 提供的普通 JMX 实现。没什么特别的。你应该试一试。
猜你喜欢
  • 2010-09-25
  • 2015-11-28
  • 1970-01-01
  • 2017-09-07
  • 2011-08-15
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多