0

我正在 RMI 中开发一个安全的银行服务,它带有一个用于服务器和客户端的 GUI。

服务器必须能够记录每个操作(新用户、已删除用户、提款、提交...)客户端将执行这些操作。由于一切都是安全的,客户首先必须在 GUI 中创建一个具有名称和密码的帐户。之后,GUI 将银行 UserList(arrayList) 中的用户添加为新客户,用户可以进行多项操作。乍一看似乎很简单,但我认为我的概念不正确。

通过RMI发送整个银行是否正确?因为起初我认为银行会成为服务器,但我找不到其他方法来做到这一点。目前,客户端 GUI 要求输入登录名和密码,并通过 RMI 接收银行。用户的特征在于密码的名称和哈希值。

private String name;
private byte[] passwordDigest;

事实上,GUI 正在做所有的安全检查,我不知道它是否相关。当您输入 login//password 时,它将在银行中搜索登录名并比较密码的哈希值。事实上,我的印象是客户知道太多信息,因为当你拥有银行时,你就拥有了一切。

它看起来是正确的还是我需要改变我的实现?

4

2 回答 2

2

您需要两个远程对象类。

第一个是通过Naming.lookup(); 它是一个单例;它包含一个login()方法。

此方法返回第二个远程对象,它不是单例,未在注册表中注册,并且为每个返回值重新创建。该对象包含所有银行业务方法以及一个logout()取消导出它的方法;它可能还实现了Unreferenced接口,因此它可以检测到死客户端,并自行取消导出。因为它每个客户端存在一次,它可以保存客户端状态,并且因为它只能通过成功的登录步骤获得,它解决了您的安全问题。

public interface Login extends Remote
{
    Session login(String username, char[] password /* or whatever */)
        throws LoginException, RemoteException;
}

public interface Session extends Remote
{
    void logout() throws RemoteException;
    void deposit(...) throws RemoteException;
    void withdraw(...) throws RemoteException;
}

public class LoginImpl extends UnicastRemoteObject implements Login
{
    public Session login(String username, char[] password)
        throws LoginException, RemoteException
    {
        // username/password check; if it fails throw a LoginException
        return new SessionImpl(username); // or whatever
    }
}

public class SessionImpl extends UnicastRemoteObject implements Session, Unreferenced
{
    public void logout() throws RemoteException
    {
        unexportObject(this, true);
    }

    public void unreferenced()
    {
        unexportObject(this, true); // needs to be in a try/catch block of course
    }

    // etc
}

我在 2001 年的书中将其描述为远程会话模式。

当然,您需要传输层安全性:请参阅javax.rmi.ssl.

于 2012-11-29T22:21:31.887 回答
1

您误解了远程接口的工作方式。客户端没有银行,它只有对银行的远程实例的引用。客户端在 Bank 接口上进行的所有方法调用实际上都变成了对 Bank 的远程实例(在服务器中运行)的远程调用。

据推测,安全检查是每个方法调用的 Bank 方法中完成的。

于 2012-11-29T18:51:11.777 回答