<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/46860.html" frameborder="0" width="468" scrolling="no" height="60"></iframe>
|
數(shù)據(jù)在網(wǎng)絡(luò)的傳輸是無所不在的,但是如果數(shù)據(jù)中包含了一些私有的信息,如:密碼或信用卡號碼,那么就要使數(shù)據(jù)對于那些未被授權(quán)的用戶保密。同樣,也要確信數(shù)據(jù)在傳輸過程中有沒有被故意或無意更改。Secure Sockets Layer(SSL) 和Transport Layer Security(TLS)協(xié)議被用來保護(hù)數(shù)據(jù)在網(wǎng)絡(luò)傳輸過程中的秘密性和完整性。
|
|
Java Secure Socket Extension(JSSE)能夠保證網(wǎng)絡(luò)的通信安全。它提供了一套框架和java版本的SSL和TLS協(xié)議的實(shí)現(xiàn),也包括了廣泛的功能,如:數(shù)據(jù)加密,服務(wù)器證明,消息完整性,以及可選的客戶證明。使用JSSE,開發(fā)者能夠提供一個基于任何協(xié)議之上(如: Hypertext Transfer Protocol(Http) , Telnet, or FTP, over TCP/IP)的客戶和服務(wù)器的安全數(shù)據(jù)通道。
|
|
JSSE是基于安全算法和握手機(jī)制之上的合成體。JSSE將危險的安全弱點(diǎn)降到最低點(diǎn),并且它減輕了開發(fā)者的負(fù)擔(dān),使得開發(fā)者可以很輕松的整合到程序中。
|
|
SSL(Secure Sockets Layer)是JSSE中的重要的部分。SSL是用的最廣泛的實(shí)現(xiàn)網(wǎng)絡(luò)的加密協(xié)議。SSL用一個密碼處理來提供網(wǎng)絡(luò)安全通信。SSL是基于標(biāo)準(zhǔn)的TCP/IP socket協(xié)議的安全增加用于網(wǎng)絡(luò)通信,所以SSL是位于傳輸層和應(yīng)用程序?qū)又g。最普通的使用SSL的是HTTP(Hypertext Transfer Protocol),用于網(wǎng)絡(luò)頁面。其他的如: Net News Transfer Protocol (NNTP), Telnet, Lightweight Directory Access Protocol (LDAP), Interactive Message Access Protocol (IMAP), and File Transfer Protocol (FTP),也能夠使用SSL。
|
TCP/IP Protocol Stack With SSL
|
|
TCP/IP Layer
|
Protocol
|
|
應(yīng)用程序?qū)?
|
HTTP, NNTP, Telnet, FTP, etc.
|
|
Secure Sockets Layer
|
SSL
|
|
傳輸層
|
TCP
|
|
網(wǎng)絡(luò)層
|
IP
|
|
|
SSL 是Netscape公司于1994年開發(fā)的。后來應(yīng)用到因特網(wǎng)成了一個標(biāo)準(zhǔn)。
|
|
SSL提供一個高標(biāo)準(zhǔn)的在客戶和服務(wù)器發(fā)送加密消息之前的SSL握手描述,如下圖:
|
|
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 363pt; HEIGHT: 294.75pt" type="#_x0000_t75" alt="Sequence of messages exchanged in SSL handshake."><imagedata src="02_6_26_2a.gif" o:href="file:///D:/j2sdk14/j2sdk-1_4_0-doc/docs/guide/security/jsse/sslmessages.gif"></imagedata></shape>
|
|
1.Client Hello: 客戶發(fā)送服務(wù)器信息,包括它所支持的密碼組。密碼組中有密碼算法和鑰匙大?。?
|
|
2.Server Hello:服務(wù)器選擇客戶和服務(wù)器都支持的密碼組到客戶。
|
|
3.Certificate: 服務(wù)器發(fā)送一個證書或一個證書鏈到客戶端,一個證書鏈開始于服務(wù)器公共鑰匙證書并結(jié)束于證明權(quán)威的根證書。這個消息是可選的,但服務(wù)器證書需要時,必須使用它。
|
|
4.Certificate request:當(dāng)服務(wù)器需要鑒別客戶時,它發(fā)送一個證書請求到客戶端。在網(wǎng)絡(luò)程序中,這個消息很少發(fā)送。
|
|
5.Server key exchange:服務(wù)器當(dāng)發(fā)送來的公共鑰匙對鑰匙交換不是很充分時,發(fā)送一個服務(wù)器鑰匙交換消息。
|
|
6.Server hello done:服務(wù)器告訴客戶完成它的初始化流通消息。
|
|
7.Certificate:假如服務(wù)器需要一個客戶證書時,客戶端發(fā)送一個證書鏈。(只有在服務(wù)器需要客戶證書時)
|
|
8.Client key exchange:客戶產(chǎn)生用于對稱算法的一個鑰匙。對RSA客戶用服務(wù)器公共鑰匙加密這個鑰匙信息并把它送到服務(wù)器。
|
|
9.Certificate verify:在網(wǎng)絡(luò)程序中,這個消息很少發(fā)送,它主要是用來允許服務(wù)器結(jié)束對客戶的鑒別處理。當(dāng)用這個消息時,客戶發(fā)送用密碼函數(shù)的數(shù)字簽名的信息到服務(wù)端,當(dāng)服務(wù)端用公共鑰匙解密這個消息時,服務(wù)器能夠鑒別客戶。
|
|
10.Change cipher spec:客戶發(fā)送一個消息告訴服務(wù)器改變加密模式。
|
|
11.Finished:客戶告訴服務(wù)器它已準(zhǔn)備安全數(shù)據(jù)通信。
|
|
12.Change cipher spec:服務(wù)器發(fā)送一個消息到客戶端并告訴客戶修改加密模式。
|
|
13.Finished:服務(wù)器告訴客戶端它已準(zhǔn)備好安全數(shù)據(jù)通信。這是client-server握手協(xié)議最后一步。
|
|
14.Encrypted data:客戶同服務(wù)器用對稱加密算法和密碼函數(shù),并用客戶發(fā)送到服務(wù)器的秘密鑰匙加密通信。
|
|
下面有一個例子可以簡單的實(shí)現(xiàn)JSSE:
|
|
import java.security.KeyStore;
|
|
import javax.security.cert.X509Certificate;
|
|
public class ClassFileServer extends ClassServer {
|
|
private static int DefaultServerPort = 2001;
|
|
public ClassFileServer(ServerSocket ss, String docroot) throws IOException
|
|
public byte[] getBytes(String path)
|
|
System.out.println("reading: " + path);
|
|
File f = new File(docroot + File.separator + path);
|
|
int length = (int)(f.length());
|
|
throw new IOException("File length is zero: " + path);
|
|
FileInputStream fin = new FileInputStream(f);
|
|
DataInputStream in = new DataInputStream(fin);
|
|
byte[] bytecodes = new byte[length];
|
|
public static void main(String args[])
|
|
"USAGE: java ClassFileServer port docroot [TLS [true]]");
|
|
"If the third argument is TLS, it will start as/n" +
|
|
"a TLS/SSL file server, otherwise, it will be/n" +
|
|
"an ordinary file server. /n" +
|
|
"If the fourth argument is true,it will require/n" +
|
|
"client authentication as well.");
|
|
int port = DefaultServerPort;
|
|
port = Integer.parseInt(args[0]);
|
|
String type = "PlainSocket";
|
|
ServerSocketFactory ssf =
|
|
ClassFileServer.getServerSocketFactory(type);
|
|
ServerSocket ss = ssf.createServerSocket(port);
|
|
if (args.length >= 4 && args[3].equals("true")) {
|
|
((SSLServerSocket)ss).setNeedClientAuth(true);
|
|
new ClassFileServer(ss, docroot);
|
|
} catch (IOException e) {
|
|
System.out.println("Unable to start ClassServer: " +
|
|
private static ServerSocketFactory getServerSocketFactory(String type) {
|
|
if (type.equals("TLS")) {
|
|
SSLServerSocketFactory ssf = null;
|
|
// set up key manager to do server authentication
|
|
char[] passphrase = "passphrase".toCharArray();
|
|
ctx = SSLContext.getInstance("TLS");
|
|
kmf = KeyManagerFactory.getInstance("SunX509");//加密算法.
|
|
ks = KeyStore.getInstance("JKS");//鑰匙存儲名字.可以用keytool工具產(chǎn)生.
|
|
ks.load(new FileInputStream("testkeys"), passphrase);//存儲鑰匙文件.
|
|
kmf.init(ks, passphrase);
|
|
ctx.init(kmf.getKeyManagers(), null, null);
|
|
ssf = ctx.getServerSocketFactory();
|
|
return ServerSocketFactory.getDefault();
|
|
public abstract class ClassServer implements Runnable {
|
|
private ServerSocket server = null;
|
|
protected ClassServer(ServerSocket ss)
|
|
public abstract byte[] getBytes(String path)
|
|
throws IOException, FileNotFoundException;
|
|
socket = server.accept();
|
|
} catch (IOException e) {
|
|
System.out.println("Class Server died: " + e.getMessage());
|
|
// create a new thread to accept the next connection
|
|
new DataOutputStream(socket.getOutputStream());
|
|
// get path to class file from header
|
|
new InputStreamReader(socket.getInputStream()));
|
|
String path = getPath(in);
|
|
byte[] bytecodes = getBytes(path);
|
|
// send bytecodes in response (assumes HTTP/1.0 or later)
|
|
out.writeBytes("HTTP/1.0 200 OK/r/n");
|
|
out.writeBytes("Content-Length: " + bytecodes.length +
|
|
out.writeBytes("Content-Type: text/html/r/n/r/n");
|
|
} catch (IOException ie) {
|
|
// write out error response
|
|
out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "/r/n");
|
|
out.writeBytes("Content-Type: text/html/r/n/r/n");
|
|
} catch (IOException ex) {
|
|
// eat exception (could log error to log file, but
|
|
// write out to stdout for now).
|
|
System.out.println("error writing response: " + ex.getMessage());
|
|
private void newListener()
|
|
(new Thread(this)).start();
|
|
private static String getPath(BufferedReader in)
|
|
String line = in.readLine();
|
|
System.out.println("line ==============="+line);
|
|
// extract class from GET line
|
|
if (line.startsWith("GET /")) {
|
|
line = line.substring(5, line.length()-1).trim();
|
|
int index = line.indexOf(' ');
|
|
path = line.substring(0, index);
|
|
// eat the rest of header
|
|
} while ((line.length() != 0) &&
|
|
(line.charAt(0) != '/r') && (line.charAt(0) != '/n'));
|
|
if (path.length() != 0) {
|
|
throw new IOException("Malformed Header");
|
|
這個服務(wù)器程序默認(rèn)的端口號是:2001,你可以將服務(wù)器根目錄設(shè)在任何目錄,如啟動服務(wù)器用: java ClassFileServer 2001(端口號) D:/j2sdk14/j2sdk-1_4_0-doc/docs/guide/security/jsse/samples(根目錄) tls(安全通信)
|
|
為了證明client –server的安全通信,可以寫一個client 程序,如下:
|
|
public class SSLSocketClient {
|
|
public static void main(String[] args) throws Exception {
|
|
SSLSocketFactory factory =
|
|
(SSLSocketFactory)SSLSocketFactory.getDefault();
|
|
(SSLSocket)factory.createSocket("localhost", 2001);
|
|
PrintWriter out = new PrintWriter(
|
|
socket.getOutputStream())));
|
|
out.println("GET http://localhost:2001/index.html HTTP/1.1");
|
|
* Make sure there were no surprises
|
|
"SSLSocketClient: java.io.PrintWriter error");
|
|
BufferedReader in = new BufferedReader(
|
|
socket.getInputStream()));
|
|
while ((inputLine = in.readLine()) != null)
|
|
System.out.println(inputLine);
|
|
我們可以運(yùn)行: java SSLSocketClient ,由于加密跟解密是非常耗時的,也許比較慢一點(diǎn)。
|
|
在這個測試程序中,我們用的算法是: SunX509,鑰匙是JKS(可以用 keytool工具添加及修改),儲存鑰匙的文件是:testkeys(可以從jdk14 文檔資料中找到)。運(yùn)行這個文件還必須要有一個證書文件samplecacerts(也可以在jdk14 文檔資料中找到),并替換
|
|
<java-home>/lib/security/cacerts,或者加上一個參數(shù): Djavax.net.ssl.trustStore=path_to_samplecacerts_file.</java-home>
|
|
Java的安全性是非常完善的,微軟的。net安全性都或多或少借鑒了java的功能。而JSSE在網(wǎng)絡(luò)上安全傳輸秘密信息是非常有用的。
|
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1907448