 |
CS 696 Emerging Technologies: Distributed Objects |
|
|---|
Spring Semester, 1998
RMI Security
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98
Contents of Doc 12, RMI Security
- References
- Security
- RMI and Security
- Creating a Custom Socket
- Creating a Custom RMISocketFactory
- Using the RMISocketFactory
- RMI & JDK1.2
- Specifying Socket Type per Object
- Server Using Specifying Own Socket
- Client
CS596
Client Server Lecture notes, Security, Spring 1997, htp://www.eli.sdsu.edu/courses/spring97/cs596/notes/security/security.html
Creatinga
Custom Socket Type,
http://www.sdsu.edu/doc/jdk1.2/docs/guide/rmi/sockettype.doc.html
Ceating
a Custom RMISocketFactory,
http://www.sdsu.edu/doc/jdk1.2/docs/guide/rmi/rmisocketfactory.doc.html
The following notes contain information taken nearly verbatim from the above
sources. However, there are some small, but important changes made at times.
What to secure
Before we can talk about security related to computers and networks, we need to
know what we are trying to secure:
- Restricted data
- Computer access (resources)
- Algorithms
- Etc.
Types of security
Some different types:
Physical security:
Prevent access to physical devices (network, computers, etc.) with:
- locks and keys
- security guard
- guard dogs
- alarm system
- etc.
Software security:
Authentication
Encryption
Audit trail
Etc.
Types of attacks
Some common methods of "attacks":
- Impersonation
- Sniffing
- Replay
- Denial of service
Authentication
Authentication is performed to ensure that a user or program has specific
access to a resource or data.
Examples:
- Unix login procedure
- SDSU modem pool login
- ATM card and PIN
- Finger printing
- "Smart" card
- etc.
The authentication process normally relies on some sort of shared (between
resource provider and resource seeker) secret or irreproducible
attribute:
- Password
- Retinal image
- Finger print
- Algorithm and key in "Smart" card
- Physical location (IP address)
Network Authentication
How is authentication over a network different?
Network packets can travel through many "unknown" (read untrusted) routers and
computers.
What are the added risks?
- Network sniffing
- Traffic logging
- Etc.
Some issues:
- Passwords, data can be "sniffed" from the network
- Traffic patterns can be analyzed
Java provides security manager to provide controls over what client or server
can do a machine
Your application needs to insure proper security manager in installed in
application
java.securtiy package is useful in encryption, etc.
Other types of security are your application's problem
RMI addresses encrypting of data over the wire
RMI Wire encryption Process
1. Create a custom socket type that does encryption
2. Create and install a socket factory in you RMI application
We will use xor encryption
- exclusive or all bytes in a stream by a mask byte
-
- the byte stream is hard to read by untrained users
-
- exclusive or all bytes a second time by the same mask byte to get original
byte stream
1. Subclass FilterOutputStream and FilterInputStream to create streams to be
used in the socket
2. Subclass java.net.Socket
3. Subclass java.net.ServerSocket
XorInputStream
public class XorInputStream extends FilterInputStream
{
byte codeMask = 0;
public XorInputStream(InputStream in, byte mask)
{
super(in);
codeMask = mask;
}
public int read() throws IOException
{
int input = in.read();
if ( input < 0 )
return input;
else
return (byte) input ^ codeMask;
}
public int read(byte inputBuffer[], int offset, int length)
throws IOException
{
byte[] codedInput = new byte[length];
int bytesRead = in.read( codedInput );
for (int k = 0; k < bytesRead;k++)
inputBuffer[offset + k ] = (byte)
(codedInput[k] ^ codeMask);
return bytesRead;
}
}
XorOutputStream
public class XorOutputStream extends FilterOutputStream
{
byte codeMask = 0;
public XorOutputStream(OutputStream out, byte mask)
{
super(out);
codeMask = mask;
}
public void write(int output) throws IOException
{
if ( output < 0 ) //not a byte,
{
out.write(output);
}
else
out.write( ((byte) output) ^ codeMask );
}
public void write(byte output[], int offset, int length)
throws IOException
{
byte[] coded = new byte[length];
for (int i = 0 ; i < length ; i++)
{
coded[i] = (byte) ( output[offset + i] ^ (byte) codeMask );
}
out.write( coded);
}
}
XorSocket
public class XorSocket extends java.net.Socket
{
/* Streams used by socket */
private InputStream in;
private OutputStream out;
private byte xorMask = 0;
public XorSocket( byte mask) // This is needed!!
throws IOException
{
super();
xorMask = mask;
}
public XorSocket(String host, int port, byte mask)
throws IOException
{
super(host, port);
xorMask = mask;
}
XorSocket - Continued
public InputStream getInputStream()
throws IOException
{
if (in == null)
{
BufferedInputStream buffered =
new BufferedInputStream( super.getInputStream() );
in = new XorInputStream( buffered , xorMask);
}
return in;
}
public OutputStream getOutputStream()
throws IOException
{
if (out == null)
{
BufferedOutputStream buffered =
new BufferedOutputStream( super.getOutputStream() );
out = new XorOutputStream(buffered, xorMask);
}
return out;
}
public synchronized void close() throws IOException
{
OutputStream out = getOutputStream();
out.flush();
super.close();
}
}
XorServerSocket
public class XorServerSocket extends ServerSocket
{
private byte xorMask = 0;
public XorServerSocket(int port, byte mask)
throws IOException
{
super(port);
xorMask = mask;
}
public XorServerSocket(int port, int backlog, byte mask)
throws IOException
{
super(port, backlog);
xorMask = mask;
}
public XorServerSocket(int port,
int backlog,
InetAddress bindAddress,
byte mask)
throws IOException
{
super(port, backlog, bindAddress);
xorMask = mask;
}
public Socket accept() throws IOException
{
Socket socket = new XorSocket( xorMask );
implAccept(socket);
return socket;
}
}
Note ServerSocket uses the Strategy and Prototype patterns
public class XorRMISocketFactory extends RMISocketFactory
{
private byte xorMask = 0;
public XorRMISocketFactory( byte mask )
{
xorMask = mask;
}
public Socket createSocket(String host, int port)
throws IOException
{
XorSocket socket =
new XorSocket(host, port, xorMask);
return socket;
}
public ServerSocket createServerSocket(int port)
throws IOException
{
XorServerSocket server =
new XorServerSocket(port, xorMask);
return server;
}
}
Interface
public interface Hello extends java.rmi.Remote
{
String sayHello() throws java.rmi.RemoteException;
}
Client
public class HelloClient
{
public static void main(String args[])
{
try
{
String server = getHelloHostAddress( args);
Hello remote = (Hello) Naming.lookup( server );
RMISocketFactory.setSocketFactory(
new XorRMISocketFactory( (byte) 0x1A ) );
String message = remote.sayHello();
System.out.println( message );
}
catch ( Exception error)
{
error.printStackTrace();
}
}
private static String getHelloHostAddress( String args[] ) throws IOException
{
ProgramProperties flags = new ProgramProperties( args );
String host = flags.getString( "host" );
String port = flags.getString( "port", "1099" );
return "rmi://" + host + ":" + port + "/HelloServer";
}
}
Server
public class HelloServer
extends UnicastRemoteObject
implements Hello
{
public HelloServer() throws RemoteException {}
public String sayHello() throws RemoteException
{ return "Hello World from someWhere" ;}
public static void main(String args[])
{
// Create and install a security manager
System.setSecurityManager(new RMISecurityManager());
try
{
String serverAddress = getHelloHostAddress( args );
HelloServer serverObject = new HelloServer();
Naming.rebind( serverAddress, serverObject);
RMISocketFactory.setSocketFactory(
new XorRMISocketFactory( (byte) 0x1A ) );
System.out.println("HelloServer bound in registry");
}
catch (Exception e)
{
System.out.println("HelloServer err: " + e);
}
}
}
Warning
The RMI Registry uses normal sockets
You must perform all interaction with the Registry before you set the socket
factory
You can only set the factory once!
The following example does not work in jdk1.1.x
You must use jdk1.2b2 or later to run this example
package whitney.rmi.examples.basic;
import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;
import sdsu.net.*;
public class MultiRMISocketFactory extends RMISocketFactory
{
/* Get the default RMISocketFactory */
private RMISocketFactory defaultFactory
= RMISocketFactory.getDefaultSocketFactory();
/*
* Override createSocket to call the default
* RMISocketFactory's createSocket method. This
* way, you'll get a TCP connection if you don't
* specify another SocketType
*/
public Socket createSocket(String host, int port)
throws IOException
{
return defaultFactory.createSocket(host, port);
}
//MultiRMISocketFactory Continued
/*
* Override createServerSocket to call the default
* RMISocketFactory's createServerSocket method.
*/
public ServerSocket createServerSocket(int port)
throws IOException
{
return defaultFactory.createServerSocket(port);
}
/*
* Override createSocket to create the type of socket
* specified by the SocketType parameter.
*/
public Socket createSocket(String host, int port,
SocketType type)
throws IOException
{
Socket socket;
String protocol = type.getProtocol();
if(protocol.equals("xor"))
{
byte[] xorMask = type.getRefData();
socket = new XorSocket(host, port, xorMask[0]);
}
else
throw new IOException("protocol " + protocol +
" not supported");
return socket;
}
//MultiRMISocketFactory Continued
/*
* Override createServerSocket to create the type of socket
* specified by the SocketType parameter.
*/
public ServerSocket createServerSocket(int port,
SocketType type)
throws IOException
{
ServerSocket server;
String protocol = type.getProtocol();
if(protocol.equals("xor"))
{
Byte xorMask = (Byte) type.getServerData();
server = new XorServerSocket(port,
xorMask.byteValue());
}
else
throw new IOException("protocol " + protocol +
" not supported");
return server;
}
}
SocketType - New in JDK 1.2
Constructor
SocketType(String protocol,
byte[] clientData, Object serverData)
Methods
equals(Object)
- Compares two Objects for equality.
getProtocol()
- Return the protocol string for this descriptor.
getRefData()
- Return the optional client data for this descriptor.
getServerData()
- Return the server-specific data for this descriptor.
hashCode()
- Returns a hash code value for the object.
read(DataInput)
- Read a descriptor from input stream.
toString()
- Returns a string representation of the object.
write(DataOutput)
- Write descriptor to output stream.
package whitney.rmi.examples.basic;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.server.*;
import sdsu.util.ProgramProperties;
import sdsu.rmi.server.*;
public class HelloServer
extends UnicastRemoteObject
implements Hello
{
public HelloServer() throws RemoteException
{
super(0, getSocketType() );
}
private static SocketType getSocketType()
{
String protocol = "xor";
byte[] forClientSide = { (byte)0xAA };
Byte forServerSide = new Byte( (byte)0xAA );
return new SocketType( protocol,
forClientSide,
forServerSide);
}
public String sayHello() throws RemoteException
{
return "Hello World from " + getUnixHostName();
}
protected static String getUnixHostName()
{
try
{
Process hostName = Runtime.getRuntime().exec( "hostname" );
BufferedReader answer = new BufferedReader(
new InputStreamReader( hostName.getInputStream()) );
hostName.waitFor();
return answer.readLine().trim();
}
catch (Exception noName)
{
return "Nameless";
}
}
private static String getHelloHostAddress( String args[] ) throws IOException
{
ProgramProperties flags = new ProgramProperties( args );
String port = flags.getString( "port", "1099" );
String host = flags.getString( "host", getUnixHostName());
return "rmi://" + ":" + port + "/HelloServer";
}
//Server Continued
public static void main(String args[])
{
// Create and install a security manager
System.setSecurityManager(new RMISecurityManager());
try
{
String serverAddress = getHelloHostAddress( args );
RMISocketFactory.setSocketFactory(
new MultiRMISocketFactory( ) );
HelloServer serverObject = new HelloServer();
Naming.rebind( serverAddress, serverObject);
System.out.println("HelloServer bound in registry");
}
catch (Exception e)
{
System.out.println("HelloServer err: ");
e.printStackTrace();
}
}
}
package whitney.rmi.examples.basic;
import java.rmi.*;
import java.net.MalformedURLException;
import java.io.IOException;
import java.rmi.server.*;
import sdsu.util.ProgramProperties;
import sdsu.rmi.server.*;
public class HelloClient
{
public static void main(String args[])
{
try
{
// Set before contacting Registry!!
RMISocketFactory.setSocketFactory(
new MultiRMISocketFactory( )
);
String server = getHelloHostAddress( args);
Hello remote = (Hello) Naming.lookup( server );
String message = remote.sayHello();
System.out.println( message );
}
catch ( Exception error)
{
error.printStackTrace();
}
}
private static String getHelloHostAddress( String args[] ) throws IOException
{
ProgramProperties flags = new ProgramProperties( args );
String host = flags.getString( "host" );
String port = flags.getString( "port", "1099" );
return "rmi://" + host + ":" + port + "/HelloServer";
}
}
visitors since 19-Feb-98