11.2 Creating Secure Client Sockets
If
you don't care very much about the underlying
details, using an encrypted SSL socket to talk to an existing secure
server is truly straightforward. Rather than constructing a
java.net.Socket object with a constructor, you get
one from a
javax.net.ssl.SSLSocketFactory using its createSocket() method.
SSLSocketFactory is an abstract class that follows
the abstract factory design pattern:
public abstract class SSLSocketFactory extends SocketFactorySince the SSLFactorySocket class is itself
abstract, you get an instance of it by invoking the static
SSLSocketFactory.getDefault() method:
public static SocketFactory getDefault( ) throws InstantiationExceptionThis either returns an instance of
SSLSocketFactory or throws an
InstantiationException if no concrete subclass can
be found. Once you have a reference to the factory, use one of these
five overloaded createSocket( ) methods to build
an SSLSocket:
public abstract Socket createSocket(String host, int port)The first two methods create and return a socket
throws IOException, UnknownHostException
public abstract Socket createSocket(InetAddress host, int port)
throws IOException
public abstract Socket createSocket(String host, int port,
InetAddress interface, int localPort)
throws IOException, UnknownHostException
public abstract Socket createSocket(InetAddress host, int port,
InetAddress interface, int localPort)
throws IOException, UnknownHostException
public abstract Socket createSocket(Socket proxy, String host, int port,
boolean autoClose) throws IOException
that's connected to the specified host and port or
throw an IOException if they
can't connect. The third and fourth methods connect
and return a socket that's connected to the
specified host and port from the specified local network interface
and port. The last createSocket( ) method,
however, is a little different. It begins with an existing
Socket object that's connected to
a proxy server. It returns a Socket that tunnels
through this proxy server to the specified host and port. The
autoClose argument determines whether the
underlying proxy socket should be closed when this
socket is closed. If autoClose is
true, the underlying socket will be closed; if
false, it won't be.The
Socket that all these methods return will really
be a javax.net.ssl.SSLSocket, a subclass of
java.net.Socket. However, you
don't need to know that. Once the secure socket has
been created, you use it just like any other socket, through its
getInputStream( ), getOutputStream(), and other methods. For example, let's
suppose there's a server running on
login.ibiblio.org on port 7,000 that accepts
orders. Each order is sent as an ASCII string using a single TCP
connection. The server accepts the order and closes the connection.
(I'm leaving out a lot of
details that would be necessary in a real-world system, such as the
server sending a response code telling the client whether the order
was accepted.) The orders that clients send look like this:
Name: John SmithThere's enough information in this message to let
Product-ID: 67X-89
Address: 1280 Deniston Blvd, NY NY 10003
Card number: 4000-1234-5678-9017
Expires: 08/05
someone snooping packets use John Smith's credit
card number for nefarious purposes. Consequently, before sending this
order, you should encrypt it; the simplest way to do that without
burdening either the server or the client with a lot of complicated,
error-prone encryption code is to use a secure socket. The following
code sends the order over a secure socket:
try {
// This statement is only needed if you didn't add
// security.provider.3=com.sun.net.ssl.internal.ssl.Provider
// to your java.security file.
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider( ));
SSLSocketFactory factory
= (SSLSocketFactory) SSLSocketFactory.getDefault( );
Socket socket = factory.createSocket("login.metalab.unc.edu", 7000);
Writer out = new OutputStreamWriter(socket.getOutputStream( ),
"ASCII");
out.write("Name: John Smith\r\n");
out.write("Product-ID: 67X-89\r\n");
out.write("Address: 1280 Deniston Blvd, NY NY 10003\r\n");
out.write("Card number: 4000-1234-5678-9017\r\n");
out.write("Expires: 08/05\r\n");
out.flush( );
out.close( );
socket.close( );
}
catch (IOException ex) {
ex.printStackTrace( );
}Only the first three statements are noticeably different from whatyou'd do with an insecure socket. The rest of the
code just uses the normal methods of the Socket,
OutputStream, and Writer
classes.Reading input is no harder. Example 11-1 is a simple
program that connects to a secure HTTP server, sends a simple GET
request, and prints out the response.
Example 11-1. HTTPSClient
import java.net.*;Here are the first few lines of output you get when you connect to
import java.io.*;
import java.security.*;
import javax.net.ssl.*;
import com.macfaq.io.*;
public class HTTPSClient {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java HTTPSClient2 host");
return;
}
int port = 443; // default https port
String host = args[0];
try {
SSLSocketFactory factory
= (SSLSocketFactory) SSLSocketFactory.getDefault( );
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
// enable all the suites
String[] supported = socket.getSupportedCipherSuites( );
socket.setEnabledCipherSuites(supported);
Writer out = new OutputStreamWriter(socket.getOutputStream( ));
// https requires the full URL in the GET line
out.write("GET http://" + host + "/ HTTP/1.1\r\n");
out.write("Host: " + host + "\r\n");
out.write("\r\n");
out.flush( );
// read response
BufferedReader in = new SafeBufferedReader(
new InputStreamReader(socket.getInputStream( )));
// read the header
String s;
while (!(s = in.readLine( )).equals(")) {
System.out.println(s);
}
System.out.println( );
// read the length
String contentLength = in.readLine( );
int length = Integer.MAX_VALUE;
try {
length = Integer.parseInt(contentLength.trim( ), 16);
}
catch (NumberFormatException ex) {
// This server doesn't send the content-length
// in the first line of the response body
}
System.out.println(contentLength);
int c;
int i = 0;
while ((c = in.read( )) != -1 && i++ < length) {
System.out.write(c);
}
System.out.println( );
out.close( );
in.close( );
socket.close( );
}
catch (IOException ex) {
System.err.println(ex);
}
}
}
the U.S. Postal Service's web site:
% java HTTPSClient www.usps.com
HTTP/1.1 200 OK
Server: Netscape-Enterprise/6.0
Date: Wed, 28 Jan 2004 18:13:08 GMT
Content-type: text/html
Set-Cookie: WEBTRENDS_ID=216.254.85.72-1075313584.16566; expires=Fri,
31-Dec-2010 00:00:00 GMT; path=/
Transfer-Encoding: chunked
b6b
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<link rel="stylesheet" href="/image/library/english/10151_styles.css"
type="text/css">
<TITLE>USPS - The United States Postal Service (U.S. Postal
Service)</TITLE>
|
it's slower to respond than you might expect.
There's a
noticeable amount of both CPU and network overhead involved in
generating and exchanging the public keys. Even over a fast
connection, it can easily take 10 seconds or more for the connection
to be established. Consequently, you probably don't
want to serve all your content over HTTPS, only the content that
really needs to be private.
• Table of Contents• Index• Reviews• Reader Reviews• Errata• AcademicJava Network Programming, 3rd EditionBy
Elliotte Rusty Harold Publisher: O'ReillyPub Date: October 2004ISBN: 0-596-00721-3Pages: 706
Thoroughly revised to cover all the 100+ significant updates
to Java Developers Kit (JDK) 1.5, Java Network
Programming is a complete introduction to
developing network programs (both applets and applications)
using Java, covering everything from networking fundamentals
to remote method invocation (RMI). It includes chapters on
TCP and UDP sockets, multicasting protocol and content
handlers, servlets, and the new I/O API. This is the
essential resource for any serious Java developer.
