gpt4 book ai didi

java - 带 SSL 的简单 RMI 服务器

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:29:14 25 4
gpt4 key购买 nike

尝试使用 SSL 加密设置一个简单的 RMI 服务器。它适用于具有 Java 服务器应用程序和 Java 客户端应用程序的简单聊天应用程序,但是,目前我什至无法使用简单的 RMI 示例让它工作!

我能让它工作的唯一方法是客户端和服务器都具有相同的信任库和 keystore 。不过对我来说,这听起来不正确,因为这意味着每个客户端也有服务器的私钥。

我关注了this guide创建信任/ keystore 。我首先尝试生成一个 keystore 和信任库,然后用 keystore 运行服务器,用信任库运行客户端。这没有用,所以我随后为每个生成一对并加载,如下面的代码所示。

它认为我可能在某处遗漏了一些明显的东西,只是我终其一生都无法弄清楚自己做错了什么。我目前有以下内容,但是在运行服务器时我得到了 errors below :

错误:

Server exception: java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.newCall(Unknown Source)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at Server.main(Server.java:38)

Hello.java

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {

String sayHello() throws RemoteException;

}

服务器.java

import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;


public class Server extends UnicastRemoteObject implements Hello {

private static final long serialVersionUID = 5186776461749320975L;

protected Server(int port) throws IOException {

super(port, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
}

@Override
public String sayHello() {
return "Hello, world!";
}

public static void main(String[] args) throws RemoteException, IllegalArgumentException {

try {

setSettings();

Server server = new Server(2020);

LocateRegistry.createRegistry(2020, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
System.out.println("RMI registry running on port " + 2020);

Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());

registry.bind("Hello", server);

} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}

}

private static void setSettings() {

String pass = "password";

System.setProperty("javax.net.ssl.debug", "all");

System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\serverkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\servertruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);




}

}

客户端.java

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.rmi.ssl.SslRMIClientSocketFactory;

public class Client {

private Client() {}

public static void main(String[] args) {

try {

setSettings();

Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());

Hello hello = (Hello) registry.lookup("Hello");

String message = hello.sayHello();

System.out.println(message);

} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}

private static void setSettings() {

String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\clientkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\clienttruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);

}

}

最佳答案

PKIX 错误意味着客户端不信任服务器证书,在这种情况下服务器是注册表。

澄清一下,您需要两个私钥和两个 keystore 来保存它们,每个一个。然后您需要在每个 keystore 中创建证书、导出它们并将它们导入到对等方的信任库中。服务器的信任库必须信任客户端的 keystore ,反之亦然。

您的代码看起来基本没问题。 createRegistry() 的结果应该存储在一个静态变量中,以防止它被 GC。无论您的 IDE 告诉您什么,您都不需要服务器类中的 serialVersionUID。它不会被序列化,至少不会被 RMI 序列化。

编辑 问题在这里:

System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks");

应该是:

System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks");

这里:

System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks"

应该是:

System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks"

编辑 2 根本问题是绑定(bind)到注册表时所需的信任库是客户端信任库,但运行服务器时所需的信任库是服务器信任库。

至少有三种可能的解决方案,按优劣顺序排列:

  1. 设置一个 SslRMIClientSocketFactory 的子类,它有自己的 SSLContext 和它自己的从客户端信任库加载的 TrustManager,并覆盖 创建套接字()。哎哟。

  2. 同时将服务器的证书导入服务器的信任库。

  3. 使用 createRegistry() 的返回值来执行 bind() 而不是在服务器中调用 getRegistry()完全避免,并避免整个问题。

关于java - 带 SSL 的简单 RMI 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21586660/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com