創(chuàng)建基于SSL的安全服務(wù)器和安全客戶的范例
站在用戶的角度思考問題,與客戶深入溝通,找到周至網(wǎng)站設(shè)計與周至網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、申請域名、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋周至地區(qū)。
以下內(nèi)容參考孫衛(wèi)琴所寫的《Java網(wǎng)絡(luò)編程核心技術(shù)詳解》一書的第15章。
源代碼下載地址為:http://lesson.javathinker.net/javanet/javanetsourcecode.rar
以下EchoServer類創(chuàng)建了一個基于SSL的安全服務(wù)器,它處于服務(wù)器模式。
/* EchoServer.java */
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.*;
public class EchoServer {
private int port=8000;
private SSLServerSocket serverSocket;
public EchoServer() throws Exception {
//輸出跟蹤日志
//System.setProperty("javax.net.debug", "all");
SSLContext context=createSSLContext();
SSLServerSocketFactory factory=context.getServerSocketFactory();
serverSocket =(SSLServerSocket)factory.createServerSocket(port);
System.out.println("服務(wù)器啟動");
System.out.println(
serverSocket.getUseClientMode()? "客戶模式":"服務(wù)器模式");
System.out.println(serverSocket.getNeedClientAuth()?
"需要驗證對方身份":"不需要驗證對方身份");
String[] supported=serverSocket.getSupportedCipherSuites();
serverSocket.setEnabledCipherSuites(supported);
}
public SSLContext createSSLContext() throws Exception {
//服務(wù)器用于證實自己身份的安全證書所在的密鑰庫
String keyStoreFile = "test.keystore";
String passphrase = "123456";
KeyStore ks = KeyStore.getInstance("JKS");
char[] password = passphrase.toCharArray();
ks.load(new FileInputStream(keyStoreFile), password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), null, null);
//當(dāng)要求客戶端提供安全證書時,服務(wù)器端可創(chuàng)建TrustManagerFactory,
//并由它創(chuàng)建TrustManager,TrustManger根據(jù)與之關(guān)聯(lián)的KeyStore中的信息,
//來決定是否相信客戶提供的安全證書。
//客戶端用于證實自己身份的安全證書所在的密鑰庫
//String trustStoreFile = "test.keystore";
//KeyStore ts = KeyStore.getInstance("JKS");
//ts.load(new FileInputStream(trustStoreFile), password);
//TrustManagerFactory tmf =
// TrustManagerFactory.getInstance("SunX509");
//tmf.init(ts);
//sslContext.init(kmf.getKeyManagers(),
// tmf.getTrustManagers(), null);
return sslContext;
}
public String echo(String msg) {
return "echo:" + msg;
}
private PrintWriter getWriter(Socket socket)throws IOException{
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut,true);
}
private BufferedReader getReader(Socket socket)throws IOException{
InputStream socketIn = socket.getInputStream();
return new BufferedReader(new InputStreamReader(socketIn));
}
public void service() {
while (true) {
Socket socket=null;
try {
socket = serverSocket.accept(); //等待客戶連接
System.out.println("New connection accepted "
+socket.getInetAddress()
+ ":" +socket.getPort());
BufferedReader br =getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println(msg);
pw.println(echo(msg));
if (msg.equals("bye")) //如果客戶發(fā)送的消息為“bye”,就結(jié)束通信
break;
}
}catch (IOException e) {
e.printStackTrace();
}finally {
try{
if(socket!=null)socket.close(); //斷開連接
}catch (IOException e) {e.printStackTrace();}
}
}
}
public static void main(String args[])throws Exception {
new EchoServer().service();
}
}
以上EchoServer類先創(chuàng)建了SSLContext對象,然后由它創(chuàng)建SSLServerSocketFactory對象,再由該工廠對象創(chuàng)建SSLServerSocket對象。對于以下程序代碼:
System.out.println(serverSocket.getUseClientMode()?
"客戶模式":"服務(wù)器模式");
System.out.println(serverSocket.getNeedClientAuth()?
"需要驗證對方身份":"不需要需要驗證對方身份");
打印結(jié)果為:
服務(wù)器模式
不需要驗證對方身份
由此可見,默認情況下,SSLServerSocket處于服務(wù)器模式,必須向?qū)Ψ阶C實自身的身份,但不需要驗證對方的身份,即不要求對方出示安全證書。
如果希望程序運行時輸出底層JSSE實現(xiàn)的日志信息,可以把“javax.net.debug”系統(tǒng)屬性設(shè)為“all”:System.setProperty("javax.net.debug", "all");
以下EchoClient類創(chuàng)建了一個基于SSL的安全客戶,它處于客戶模式。
/* EchoClient.java */
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.*;
public class EchoClient {
private String host="localhost";
private int port=8000;
private SSLSocket socket;
public EchoClient()throws IOException{
SSLContext context=createSSLContext();
SSLSocketFactory factory=context.getSocketFactory();
socket=(SSLSocket)factory.createSocket(host,port);
String[] supported=socket.getSupportedCipherSuites();
socket.setEnabledCipherSuites(supported);
System.out.println(socket.getUseClientMode()?
"客戶模式":"服務(wù)器模式");
}
public SSLContext createSSLContext() throws Exception {
String passphrase = "123456";
char[] password = passphrase.toCharArray();
//設(shè)置客戶端所信任的安全證書所在的密鑰庫
String trustStoreFile = "test.keystore";
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(new FileInputStream(trustStoreFile), password);
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null,tmf.getTrustManagers(), null);
return sslContext;
}
public static void main(String args[])throws IOException{
new EchoClient().talk();
}
private PrintWriter getWriter(Socket socket)throws IOException{
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut,true);
}
private BufferedReader getReader(Socket socket)throws IOException{
InputStream socketIn = socket.getInputStream();
return new BufferedReader(new InputStreamReader(socketIn));
}
public void talk()throws IOException {
try{
BufferedReader br=getReader(socket);
PrintWriter pw=getWriter(socket);
BufferedReader localReader=
new BufferedReader(new InputStreamReader(System.in));
String msg=null;
while((msg=localReader.readLine())!=null){
pw.println(msg);
System.out.println(br.readLine());
if(msg.equals("bye"))
break;
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{socket.close();}catch(IOException e){e.printStackTrace();}
}
}
}
以上EchoClient類先創(chuàng)建了一個SSLSocketFactory對象,然后由它創(chuàng)建了SSLSocket對象。對于以下程序代碼:
System.out.println(socket.getUseClientMode()?
"客戶模式":"服務(wù)器模式");
打印結(jié)果為:
客戶模式
由此可見,默認情況下,由SSLSocketFactory創(chuàng)建的SSLSocket對象處于客戶模式,不必向?qū)Ψ阶C實自身的身份。
EchoClient類依靠TrustManager來決定是否信任EchoServer出示的安全證書。EchoClient類的SSLSocketFactory對象是由SSLContext對象來創(chuàng)建的。這個SSLContext對象通過TrustManager來管理所信任的安全證書。在本例中,TrustManager所信任的安全證書位于test.keystore密鑰庫文件中。
在本例中,服務(wù)器端向客戶端出示的安全證書位于test.keystore密鑰庫文件中。在實際應(yīng)用中,服務(wù)器端的密鑰庫文件中包含密鑰對,從安全角度出發(fā),客戶端所信任的密鑰庫文件中應(yīng)該僅僅包含公鑰,所以服務(wù)器和客戶端應(yīng)該使用不同的密鑰庫文件。
假定該文件與EchoServer.class以及EchoClient.class文件位于同一目錄下。在DOS命令行中轉(zhuǎn)到范例所在的chapter15目錄下,按照以下步驟運行EchoServer和EchoClient:
(1)設(shè)置classpath,運行命令“set classpath=C:\chapter15\classes”。
(2)運行“start java EchoServer”命令,啟動EchoServer服務(wù)器。
(3)運行“ java EchoClient”命令,啟動EchoClient客戶。