我如何让套接字只接受来自本地主机的连接(在 Java 中)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/99020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 11:02:11  来源:igfitidea点击:

How do I have a socket accept connections only from the localhost (in Java)?

javasocketslocalhostloopbackserversocket

提问by

I have a java app (not running in any application container) which listens on a ServerSocket for connections. I would like it to only accept connections which come from localhost. Currently, after a connection is accepted, it checks the peer IP and rejects it if it is not the loopback address, but I know that peer IP addresses can be spoofed. So, if possible, I'd prefer to bind to a socket that only listens on the loopback interface; is this possible?

我有一个 java 应用程序(不在任何应用程序容器中运行),它在 ServerSocket 上侦听连接。我希望它只接受来自本地主机的连接。目前,在接受连接后,它会检查对等 IP,如果它不是环回地址,则拒绝它,但我知道对等 IP 地址可以被欺骗。所以,如果可能的话,我更愿意绑定到一个只侦听环回接口的套接字;这可能吗?

I've tried a few different things (such as specifying "127.0.0.1" as the local address when calling bind()) with no luck. Thanks in advance.

我尝试了一些不同的事情(例如在调用 bind() 时将“127.0.0.1”指定为本地地址),但都没有成功。提前致谢。



Thank you all for your help. I'm embarrassed to admit that this was all my mistake. Our application listens on two different ports, and I was binding one to the loopback interface but testing against the other. When I actually try to telnet to the correct port, everything works fine (i.e., binding to "127.0.0.1" does exactly what it's supposed to).

谢谢大家的帮助。我很尴尬地承认这都是我的错。我们的应用程序侦听两个不同的端口,我将一个端口绑定到环回接口,但对另一个端口进行了测试。当我真正尝试 telnet 到正确的端口时,一切正常(即绑定到“127.0.0.1”完全符合预期)。

As for spoofing the loopback address, you guys are right. I shouldn't have made it sound like the primary concern. Really, the desired behavior is to only take local connections, and binding to only the local interface is a more direct way of achieving that than accepting all connections and then closing non-local ones.

至于欺骗回环地址,你们是对的。我不应该让它听起来像主要问题。确实,所需的行为是仅采用本地连接,并且仅绑定到本地接口是实现这一目标的更直接方式,而不是接受所有连接然后关闭非本地连接。

回答by Jerub

Peer IP addresses cannot be spoofed in this manner, have you nothing to fear from using the technique of inspecting the peer and deciding to drop the connection during establishment.

对等 IP 地址无法以这种方式被欺骗,您无需担心使用检查对等点并在建立期间决定断开连接的技术。

However: binding to 127.0.0.1 should work, and cause the operating system to tell the connecting host that there is nothing listening if they connect on one of the systems other ip addresses. Can you amend this question with a compilable example? Perhaps you've made a simple error.

但是:绑定到 127.0.0.1 应该可以工作,并导致操作系统告诉连接主机,如果它们连接到其他 IP 地址的系统之一上,则没有任何监听。你能用一个可编译的例子来修改这个问题吗?也许你犯了一个简单的错误。

回答by paxdiablo

You could, as you already seem to be doing, accept() the connection anyway then use getInetAddress() to ensure the address is an authorized one. If not, simply close() the socket straight away. 127.0.0.1is notan address that can be spoofed.

您可以像您已经在做的那样,无论如何都接受()连接,然后使用 getInetAddress() 来确保地址是经过授权的地址。如果没有,只需立即关闭()套接字。127.0.0.1不是可以被欺骗的地址。

Alternatively, you could install your own security manager which will have its checkAccept() method called with the address and port of the remote site. Thet's a little harder - I've never tried since the first solution has always been adequate for me.

或者,您可以安装自己的安全管理器,该管理器将使用远程站点的地址和端口调用 checkAccept() 方法。这有点难 - 我从来没有尝试过,因为第一个解决方案对我来说已经足够了。

回答by Tom Hawtin - tackline

If the peer address is spoofed, then there is nothing further that you can do.

如果对等地址被欺骗,则您无能为力。

However, to spoof 127.0.0.1 is not easy. You would have to have a TCP/IP stack dumb enough to accept such a packet. There would be no way of the spoofer receiving packets back. On a good TCP/IP stack, it should not be able to guess the sequence numbers so it can't keep up with the expected conversation.

然而,欺骗 127.0.0.1 并不容易。您必须有一个足够笨拙的 TCP/IP 堆栈才能接受这样的数据包。欺骗者将无法接收数据包。在一个好的 TCP/IP 堆栈上,它不应该能够猜测序列号,因此它无法跟上预期的对话。

回答by Selfmade Javaman

if (socket.getInetAddress().isLoopbackAddress()){
    //Your code goes here
}

回答by Steve Moyer

When you bind your ServerSocket, specifying localhost should make the TCP/IP stack reject the connection. Even if this isn't working on your system, localhost can't (okay, maybe if someone hacked your TCP/IP stack and the default gateway router) be spoofed, since that address isn't routed through the physical interface.

绑定 ServerSocket 时,指定 localhost 应该会使 TCP/IP 堆栈拒绝连接。即使这在您的系统上不起作用,本地主机也不能(好吧,也许如果有人入侵了您的 TCP/IP 堆栈和默认网关路由器)被欺骗,因为该地址不是通过物理接口路由的。

I am curious as to why your binding doesn't succeed, what is your OS, Java version, etc?

我很好奇为什么您的绑定没有成功,您的操作系统、Java 版本等是什么?