Java HTTPS SSL介绍

https简介:
    它是内置于其浏览器中,用于对数据进行压缩和解压操作,并返回网络上传送回的结果。HTTPS实际上应用了安全套接字层(SSL)作为HTTP应用层的子层。(HTTPS使用端口443,而HTTP使用端口80来和TCP/IP进行通信。)SSL使用40 位关键字作为RC4流加密算法,这对于商业信息的加密是合适的。HTTPS和SSL支持使用X.509数字认证,如果需要的话用户可以确认发送者是谁。
    也就是说它的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

HTTPS和HTTP的区别:
  一、https协议需要到ca申请证书,一般免费证书很少,需要交费。
  二、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
  三、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
四、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

HTTPS解决的问题:

一、信任主机的问题
   采用https的服务器必须从CA (Certificate Authority)申请一个用于证明服务器用途类型的证书。该证书只有用于对应的服务器的时候,客户端才信任此主机。客户通过信任该证书,从而信任了该主机。其实这样做效率很低,但是更侧重安全。
    由于证书是分等级的,网站拥有者可能从根证书颁发机构领到证书,也可能从根证书的下一级(如某个国家的认证中心,或者是某个省发出的证书)领到证书。假设我们正在访问某个使用了 SSL技术的网站,IE浏览器就会收到了一个SSL证书,如果这个证书是由根证书颁发机构签发的,IE浏览器就会按照下面的步骤来检查:浏览器使用内置的根证书中的公钥来对收到的证书进行认证,如果一致,就表示该安全证书是由可信任的颁证机构签发的,这个网站就是安全可靠的;如果该SSL证书不是根服务器签发的,浏览器就会自动检查上一级的发证机构,直到找到相应的根证书颁发机构,如果该根证书颁发机构是可信的,这个网站的SSL证书也是可信的。

二、通讯过程中的数据的泄密和被篡改
  一般意义上的https,就是服务器有一个证书。
  a) 主要目的是保证服务器就是他声称的服务器。
  b) 服务端和客户端之间的所有通讯,都是加密的。
  i. 具体讲,是客户端产生一个对称的密钥,通过服务器的证书来交换密钥,即一般意义上的握手过程。
  ii. 接下来所有的信息往来就都是加密的。第三方即使截获,也没有任何意义,因为他没有密钥,当然篡改也就没有什么意义了。

SSL介绍:

    用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截获及篡改,目前一般通用之规格为40 bit之安全标准。
    当前版本为3.0。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。
    SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层:
   SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
   SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

SSL协议提供的服务主要有哪些?
  1)认证用户和服务器,确保数据发送到正确的客户机和服务器
  2)加密数据以防止数据中途被窃取
  3)维护数据的完整性,确保数据在传输过程中不被改变。
SSL协议的工作流程
    服务器认证阶段:
    1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接;
    2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;
    3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;
    4)服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。

    用户认证阶段:
    在此之前,服务器已经通过了客户认证,这一阶段主要完成对客户的认证。经认证的服务器发送一个提问给客户,客户则返回(数字)签名后的提问和其公开密钥,从而向服务器提供认证。

SSL协议的握手过程:

    ①客户端的浏览器向服务器传送客户端SSL协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。
    ②服务器向客户端传送SSL协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。
    ③客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过,通讯将断开;如果合法性验证通过,将继续进行第四步。
    ④用户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤②中的服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。
    ⑤如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。
    ⑥如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的CA 是否可靠,发行CA 的公钥能否正确解开客户证书的发行CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。
    ⑦服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于SSL协议的安全数据通讯的加解密通讯。同时在SSL通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。
    ⑧客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。
    ⑨服务器向客户端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。
    ⑩SSL的握手部分结束,SSL安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。

加密技术简介:
    加密技术包括两个元素:算法和密钥。
    算法是将普通的文本(或者可以理解的信息)与一串数字(密钥)的结合,产生不可理解的密文的步骤,密钥是用来对数据进行编码和解码的一种算法。在安全保密中,可通过适当的密钥加密技术和管理机制来保证网络的信息通讯安全。
    密钥加密技术的密码体制分为对称密钥体制和非对称密钥体制两种。相应地,对数据加密的技术分为两类,即对称加密(私人密钥加密)和非对称加密(公开密钥加密)。对称加密以数据加密标准(DES,Data Encryption Standard)算法为典型代表,非对称加密通常以RSA(Rivest Shamir Ad1eman)算法为代表。对称加密的加密密钥和解密密钥相同,而非对称加密的加密密钥和解密密钥不同,加密密钥可以公开而解密密钥需要保密。
    对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥,即加密密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,而且对计算机功能要求也没有那么高。IDEA加密标准由PGP(Pretty Good Privacy)系统使用。
     1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。相对于“对称加密算法”这种方法也叫做“非对称加密算法”。与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密 (privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

Java SSL Socket实例:

package com.maosheng.https;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

/*
*SSL Socket的服务器端
*/

public class SSLServer {
public static void startSSLServer() throws IOException {
int port = 6666;// 监听端口
String keyFile = "c:\\cert\\serverkey.jks";// 密钥库文件
String keyFilePass = "changeit";// 密钥库的密码
String keyPass = "changeit";// 密钥别名的密码
SSLServerSocket sslsocket = null;// 安全连接套接字
KeyStore ks;// 密钥库
KeyManagerFactory kmf;// 密钥管理工厂
SSLContext sslc = null;// 安全连接方式
// 初始化安全连接的密钥
try {
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyFile), keyFilePass.toCharArray());
// 创建管理JKS密钥库的X.509密钥管理器
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPass.toCharArray());
// 构造SSL环境,指定SSL版本为3.0,也可以使用TLSv1,但是SSLv3更加常用
sslc = SSLContext.getInstance("SSLv3");
// 初始化SSL环境。第二个参数是告诉JSSE使用的可信任证书的来源,
// 设置为null是从javax.net.ssl.trustStore中获得证书。第三个参数是JSSE生成的随机数,
// 这个参数将影响系统的安全性,设置为null是个好选择,可以保证JSSE的安全性。
sslc.init(kmf.getKeyManagers(), null, null);
} catch (KeyManagementException ex) {

} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 用安全连接的工厂来创建安全连接套接字
SSLServerSocketFactory sslssf = sslc.getServerSocketFactory();
sslsocket = (SSLServerSocket) sslssf.createServerSocket();// 创建并进入监听
SocketAddress sa = new InetSocketAddress("localhost", port);
sslsocket.bind(sa);
System.out.println("Listening...");
SSLSocket ssocket = (SSLSocket) sslsocket.accept();// 接受客户端的连接
System.out.println("Server Connection OK~");
System.out.println("========================");
System.out.println("");
// 以下代码同socket通讯实例中的代码
BufferedReader socketIn = new BufferedReader(new InputStreamReader(
ssocket.getInputStream()));
BufferedReader userIn = new BufferedReader(new InputStreamReader(
System.in));
PrintStream socketOut = new PrintStream(ssocket.getOutputStream());
String s;
while (true) {
System.out.println("Please wait client 's message..");
System.out.println("");
s = socketIn.readLine();
System.out.println("Client Message: " + s);
if (s.trim().equals("BYE"))
break;
System.out.print("Server Message: ");
s = userIn.readLine();
socketOut.println(s);
if (s.trim().equals("BYE"))
break;
}
socketIn.close();
socketOut.close();
userIn.close();
sslsocket.close();
}

public static void main(String[] args) {
try {
startSSLServer();
} catch (Exception e) {
System.out.println("Error: " + e);
}
}
}

package com.maosheng.https;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

import javax.net.ssl.SSLSocketFactory;

/*
*SSL Socket的客户端
*/
public class SSLClient {
static int port = 6666;

public static void startSSLClient() throws IOException {
int port = 6666;// 要连接的服务器端口
String serverAdd = "localhost";// 要连接的服务器地址192.168.1.39
try {
System.setProperty("javax.net.ssl.trustStore", "c:\\cert\\serverkey.jks");//设置可信任的密钥仓库
System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); // 设置可信任的密钥仓库的密码
SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory
.getDefault();// 利用工厂来创建SSLSocket安全套接字
Socket csocket = sslsf.createSocket(serverAdd, port);// 创建并连接服务器
System.out.println("Client OK~");
System.out.println("===============");
System.out.println("");
// 以下代码同socket通讯实例中的代码
BufferedReader socketIn = new BufferedReader(new InputStreamReader(
csocket.getInputStream()));// 接受到的信息
PrintStream socketOut = new PrintStream(csocket.getOutputStream());// 要发送的信息
BufferedReader userIn = new BufferedReader(new InputStreamReader(
System.in));// 用户输入信息
String s;
while (true) {
System.out.print("Client Message: ");
s = userIn.readLine();
socketOut.println(s);
if (s.trim().equals("BYE"))
break;
else {
System.out.println("Please wait Server Message..");
System.out.println("");
}
s = socketIn.readLine();
System.out.println("Server Message: " + s);
if (s.trim().equals("BYE"))
break;
}
socketIn.close();
socketOut.close();
userIn.close();
csocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
try {
startSSLClient();
} catch (Exception e) {
System.out.println("Error: " + e);
}
}
}

Java SSL Socket双向认证:

总体思路步骤是
    1.分别生成客户端和服务器端密钥库
keytool -genkey -keystore c:\client.jks -keyalg rsa -alias ssl1 -validity 700
keytool -genkey -keystore c:\serv.jks -keyalg rsa -alias ssl1 –validity 700

   2.客户端与服务器端各自导出证书
keytool -export -alias ssl1 -file c:\ssl1.cer -keystore c:\serv.jks
keytool -export -alias ssl1 -file c:\ssl2.cer -keystore c:\client.jks

   3.交换证书 导入到各自的密钥库
keytool -import -file c:\ssl1.cer -keystore c:\client.jks
keytool -import -file c:\ssl2.cer -keystore c:\serv.jks

当任意一端删除对方导入的证书 则连接不会成功,这里不再写出。

--------------------------------server-------------------------

public static void main(String[] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore tks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("c:/serv.jks"),
"changeit".toCharArray());
tks.load(new FileInputStream("c:/serv.jks"),
"changeit".toCharArray());
kmf.init(ks, "changeit".toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLServerSocket serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(26666);
serverSocket.setNeedClientAuth(true);
Socket ssls=serverSocket.accept();

// 以下代码同socket通讯实例中的代码
BufferedReader socketIn = new BufferedReader(new InputStreamReader(
ssls.getInputStream()));
BufferedReader userIn = new BufferedReader(new InputStreamReader(
System.in));
PrintStream socketOut = new PrintStream(ssls.getOutputStream());
String s;
while (true) {
System.out.println("Please wait client 's message..");
System.out.println("");
s = socketIn.readLine();
System.out.println("Client Message: " + s);
if (s.trim().equals("BYE"))
break;
System.out.print("Server Message: ");
s = userIn.readLine();
socketOut.println(s);
if (s.trim().equals("BYE"))
break;
}
socketIn.close();
socketOut.close();
userIn.close();
ssls.close();

}


----------------------------------client-------------------------
public static void main(String[] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("SSL"); 
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
KeyStore ks = KeyStore.getInstance("JKS"); 
KeyStore tks = KeyStore.getInstance("JKS"); 
ks.load(new FileInputStream("c:/client.jks"), "changeit".toCharArray()); 
tks.load(new FileInputStream("c:/client.jks"),"changeit".toCharArray()); 
kmf.init(ks, "changeit".toCharArray()); 
tmf.init(tks); 
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 
SSLSocket csocket= (SSLSocket) ctx.getSocketFactory().createSocket("localhost", 26666);


System.out.println("Client OK~");
System.out.println("===============");
System.out.println("");
// 以下代码同socket通讯实例中的代码
BufferedReader socketIn = new BufferedReader(new InputStreamReader(
csocket.getInputStream()));// 接受到的信息
PrintStream socketOut = new PrintStream(csocket.getOutputStream());// 要发送的信息
BufferedReader userIn = new BufferedReader(new InputStreamReader(
System.in));// 用户输入信息
String s;
while (true) {
System.out.print("Client Message: ");
s = userIn.readLine();
socketOut.println(s);
if (s.trim().equals("BYE"))
break;
else {
System.out.println("Please wait Server Message..");
System.out.println("");
}
s = socketIn.readLine();
System.out.println("Server Message: " + s);
if (s.trim().equals("BYE"))
break;
}
socketIn.close();
socketOut.close();
userIn.close();
csocket.close();

}

你可能感兴趣的:(java)