java 是否可以将普通套接字更改为 SSLSocket?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6559859/
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-30 16:22:11  来源:igfitidea点击:

Is it possible to change plain socket to SSLSocket?

javassl

提问by sodarfish

There is a plain socket server listening on port 12345;

有一个普通的套接字服务器监听端口12345

ServerSocket s = new ServerSocket(12345);

What I want to know is that it is possible that:

我想知道的是,有可能:

  1. If the client send a httprequest, the server handle the request directly,
  2. If the client send a httpsrequest, the server change client socket to SSLSocket?
  1. 如果客户端发送http请求,服务器直接处理请求,
  2. 如果客户端发送https请求,服务器将客户端套接字更改为 SSLSocket?

Thanks

谢谢

回答by Bruno

Is it possible to change plain socket to SSLSocket?

是否可以将普通套接字更改为 SSLSocket?

Yes, it is. On the server side, the following works:

是的。在服务器端,以下工作:

ServerSocketFactory ssf = ServerSocketFactory.getDefault();
ServerSocket serverSocket = ssf.createServerSocket(12345);

// I've initialised an sslContext with a keystore, as you normally would.
Socket socket = serverSocket.accept();
SSLSocketFactory sslSf = sslContext.getSocketFactory();
// The host name doesn't really matter, since we're turning it into a server socket
// (No need to match the host name to the certificate on this side).
SSLSocket sslSocket = (SSLSocket) sslSf.createSocket(socket, null,
    socket.getPort(), false);
sslSocket.setUseClientMode(false);

// Use the sslSocket InputStream/OutputStream as usual.

SSLSocketFactory.createSocket(Socket, ...)will by default convert the existing Socketinto a client-mode SSLSocket. Since the handshake only starts when you start reading/writing with the I/O streams, it's still time to change the mode using setUseClientMode(false).

SSLSocketFactory.createSocket(Socket, ...)默认情况下将现有的Socket转换为客户端模式SSLSocket。由于握手仅在您开始使用 I/O 流进行读/写时才开始,因此现在仍然需要使用setUseClientMode(false).

Regarding the rest of the question:

关于问题的其余部分:

What I want to know is that it is possible that:

  • If the client send a http request, the server handle the request directly,
  • If the client send a https request, the server change client socket to SSLSocket?

我想知道的是,有可能:

  • 如果客户端发送http请求,服务器直接处理请求,
  • 如果客户端发送 https 请求,服务器将客户端套接字更改为 SSLSocket?

Again, yes, it's possible. It's sometimes referred to as "port unification" and it's implemented in Grizzlyand thus Glassfish.

再次,是的,这是可能的。它有时被称为“端口统一”,它在 GrizzlyGlassfish 中实现

It works because both HTTP and TLS (upon which HTTPS works) are protocols where the client is expected to talk first. Therefore, the server can detect whether what the client initially sends is a TLS ClientHellomessage (in which case it should try to proceed with the TLS handshake) or a plain HTTP request (e.g. GET / HTTP/1.1...).

它之所以有效,是因为 HTTP 和 TLS(HTTPS 的工作原理)都是客户端应该首先进行通信的协议。因此,服务器可以检测客户端最初发送的是 TLSClientHello消息(在这种情况下,它应该尝试继续进行 TLS 握手)还是普通的 HTTP 请求(例如GET / HTTP/1.1……)。

I suspect port unification is "easier" to do using SSLEngine, otherwise, it might be hard to implement a read-ahead on a plain socket, which you would still be able to convert via SSLSocketFactory.createSocket(Socket, ...).

我怀疑端口统一是“容易”做使用SSLEngine,否则,它可能是难以实现的一个普通的插座,你仍然可以通过转换预读SSLSocketFactory.createSocket(Socket, ...)

Note that this is still rather unusual, though.

请注意,这仍然很不寻常。

回答by Soulman

It is not possible to serve both http and https on the same port.However, it should in theory be possible to upgrade an existing http connection to use TLS if both the client and server supports it, see RFC 2817. The SSLSocketFactory class has a createSocket() function which can be used to upgrade an existing socket to SSL/TLS.

无法在同一端口上同时提供 http 和 https 服务。但是,如果客户端和服务器都支持 TLS,理论上应该可以升级现有的 http 连接以使用 TLS,请参阅RFC 2817。SSLSocketFactory 类具有 createSocket() 函数,可用于将现有套接字升级到 SSL/TLS。

Disclaimer: I have not attempted to do this, and implementing RFC 2817 is likely non-trivial.

免责声明:我没有尝试这样做,并且实施 RFC 2817 可能并非易事。

Edit:Apparently I was wrong, like Bruno wrote it is possible to serve http and https on the same port using a technology called port unification, which uses the first few bytes received to detect the protocol. There is an exampleof this included with the Netty (JBoss) framework.

编辑:显然我错了,就像布鲁诺写的那样,可以使用称为端口统一的技术在同一端口上提供 http 和 https 服务,该技术使用接收到的前几个字节来检测协议。Netty (JBoss) 框架中包含了一个示例

回答by Pa?lo Ebermann

The Socket/SSLSocket interface does not allow convenient content-recognition here - when you start reading from a socket and see that it is only garbage (not plain HTTP), you can't supply this data to a new SSLSocket wrapped around a normal one.

Socket/SSLSocket 接口在这里不允许方便的内容识别 - 当您开始从套接字读取并看到它只是垃圾(不是普通的 HTTP)时,您无法将此数据提供给一个新的 SSLSocket 包裹在一个普通的 SSLSocket 周围.

You could use a Socket (or SocketChannel) and look at the data, and then (if it is not the start of a plain HTTP request) pass the same data to an SSLEngine object for decryption/encryption. This means that you have to handle all the encryption/decryption calls yourself, which is not totally trivial (at least, it is a lot more complicated than simply using an SSLSocket with it's two streams - I did it once).

您可以使用 Socket(或 SocketChannel)并查看数据,然后(如果它不是普通 HTTP 请求的开始)将相同的数据传递给 SSLEngine 对象以进行解密/加密。这意味着您必须自己处理所有加密/解密调用,这并非完全微不足道(至少,它比简单地使用带有两个流的 SSLSocket 复杂得多——我做过一次)。

Of course, if you do this, you would likely better implement the RFC 2817 interface, instead of trying automated content sniffing.

当然,如果您这样做,您可能会更好地实现 RFC 2817 接口,而不是尝试自动内容嗅探。

回答by duffymo

I think it's no on both counts, based on what you've posted.

根据您发布的内容,我认为这两者都不是。

  1. If the listener on the ServerSocketis not interpreting the request as HTTP, then there's no magic that will make it so.
  2. If the listener on the ServerSocketis not decrypting the encrypted request, then there's no magic that will make it so.
  1. 如果 上的侦听ServerSocket器没有将请求解释为 HTTP,那么就没有魔法可以做到这一点。
  2. 如果 上的侦听ServerSocket器没有解密加密的请求,那么就没有魔法可以做到这一点。

Did you write the code that's listening on the ServerSocket? If yes, you can answer your own question by looking at your code.

您是否编写了正在侦听的代码ServerSocket?如果是,您可以通过查看您的代码来回答您自己的问题。

Did someone else write the code that's listening on the ServerSocket? If yes, you'll have to ask them. Were you given any information about the expected protocol?

其他人是否编写了正在侦听的代码ServerSocket?如果是的话,你得问他们。您是否获得了有关预期协议的任何信息?