概念
- 安全套接層SSL(Secure Sockets Layer )或傳輸層安全TLS(Transport Layer Security)是為網(wǎng)絡(luò)通信提供安全及數(shù)據(jù)完整性的一種安全協(xié)議,用于在傳輸層對此次網(wǎng)絡(luò)連接采用對稱算法或非對稱算法進行加密,保證信息安全。
- TLS 是SSL 的標(biāo)準(zhǔn)化后的產(chǎn)物,有1.0 ,1.1 ,1.2 三個版本,默認使用1.0。TLS1.0 和SSL3.0 幾乎沒有區(qū)別,事實上我們現(xiàn)在用的都是TLS,但因為歷史上習(xí)慣了SSL 這個稱呼。
- SSL協(xié)議位于TCP/IP協(xié)議與各種應(yīng)用層協(xié)議之間,為數(shù)據(jù)通訊提供安全支持,SSL協(xié)議可分為兩層:
- SSL記錄協(xié)議(SSL Record Protocol)——它建立在可靠的傳輸協(xié)議(比如TCP)之上,為高層協(xié)議提供數(shù)據(jù)封裝、壓縮、加密等基本功能的支持。
- SSL握手協(xié)議(SSL Handshake Protocol)——它建立在SSL記錄協(xié)議之上,用于在實際的數(shù)據(jù)傳輸開始前,通訊雙方進行身份認證、協(xié)商加密算法、交換加密密鑰等。
作用
- 認證用戶和服務(wù)器,確保數(shù)據(jù)發(fā)送到正確的客戶機和服務(wù)器
- 加密數(shù)據(jù)以防止數(shù)據(jù)中途被竊取
- 維護數(shù)據(jù)的完整性,確保數(shù)據(jù)在傳輸過程中不被改變。
工作原理
- 通過CA體系交換public key
- 通過非對稱加密算法,交換用于對稱加密的密鑰
- 通過對稱加密算法,加密正常的網(wǎng)絡(luò)通信
非對稱加密
非對稱加密算法是一種密鑰的保密方法。
非對稱加密算法需要兩個密鑰:公開密鑰(public key:簡稱公鑰)和私有密鑰(private key:簡稱私鑰)。公鑰與私鑰是一對,如果用公鑰對數(shù)據(jù)進行加密,只有用對應(yīng)的私鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
非對稱加密算法實現(xiàn)機密信息交換的基本過程是:甲方生成一對密鑰并將公鑰公開,需要向甲方發(fā)送信息的其他角色(乙方)使用該密鑰(甲方的公鑰)對機密信息進行加密后再發(fā)送給甲方;甲方再用自己私鑰對加密后的信息進行解密。甲方想要回復(fù)乙方時正好相反,使用乙方的公鑰對數(shù)據(jù)進行加密,同理,乙方使用自己的私鑰來進行解密。另一方面,甲方可以使用自己的私鑰對機密信息進行簽名后再發(fā)送給乙方;乙方再用甲方的公鑰對甲方發(fā)送回來的數(shù)據(jù)進行驗簽。
CA
CA(Certificate Authority)即頒發(fā)數(shù)字證書的機構(gòu)。是負責(zé)發(fā)放和管理數(shù)字證書的權(quán)威機構(gòu),并作為電子商務(wù)交易中受信任的第三方,承擔(dān)公鑰體系中公鑰的合法性檢驗的責(zé)任。
為了保證CA證書不被劫持,CA證書一般都是預(yù)存在操作系統(tǒng)或者瀏覽器中的。
工作流程

步驟 1. ClientHello – 客戶端發(fā)送所支持的 SSL/TLS 最高協(xié)議版本號和所支持的加密算法集合及壓縮方法集合等信息給服務(wù)器端。
步驟 2. ServerHello – 服務(wù)器端收到客戶端信息后,選定雙方都能夠支持的 SSL/TLS 協(xié)議版本和加密方法及壓縮方法,返回給客戶端。
(可選)步驟 3. SendCertificate – 服務(wù)器端發(fā)送服務(wù)端證書給客戶端。
(可選)步驟 4. RequestCertificate – 如果選擇雙向驗證,服務(wù)器端向客戶端請求客戶端證書。
步驟 5. ServerHelloDone – 服務(wù)器端通知客戶端初始協(xié)商結(jié)束。
(可選)步驟 6. ResponseCertificate – 如果選擇雙向驗證,客戶端向服務(wù)器端發(fā)送客戶端證書。
步驟 7. ClientKeyExchange – 客戶端使用服務(wù)器端的公鑰,對客戶端公鑰和密鑰種子進行加密,再發(fā)送給服務(wù)器端。
(可選)步驟 8. CertificateVerify – 如果選擇雙向驗證,客戶端用本地私鑰生成數(shù)字簽名,并發(fā)送給服務(wù)器端,讓其通過收到的客戶端公鑰進行身份驗證。
步驟 9. CreateSecretKey – 通訊雙方基于密鑰種子等信息生成通訊密鑰。
步驟 10. ChangeCipherSpec – 客戶端通知服務(wù)器端已將通訊方式切換到加密模式。
步驟 11. Finished – 客戶端做好加密通訊的準(zhǔn)備。
步驟 12. ChangeCipherSpec – 服務(wù)器端通知客戶端已將通訊方式切換到加密模式。
步驟 13. Finished – 服務(wù)器做好加密通訊的準(zhǔn)備。
步驟 14. Encrypted/DecryptedData – 雙方使用客戶端密鑰,通過對稱加密算法對通訊內(nèi)容進行加密。
步驟 15. ClosedConnection – 通訊結(jié)束后,任何一方發(fā)出斷開 SSL 連接的消息。
示例
public class GreetingSSL {
private static final int SEV_PORT = 2090;
// 服務(wù)器端授權(quán)的用戶名和密碼
private static final String USER_NAME = "Lily";
private static final String PASSWORD = "Lily";
public static void main(String[] args) {
// 需要分別配置客戶端和服務(wù)端的證書,才可以運行
try {
// 開啟服務(wù)端
SSLServer server = new SSLServer();
server.start();
// 開啟客戶端1
SSLClient client1 = new SSLClient();
client1.connect();
} catch (IOException e) {
e.printStackTrace();
}
}
private static class SSLServer extends Thread {
// 服務(wù)器端保密內(nèi)容
private static final String SECRET_CONTENT = "This content is secret!";
private SSLServerSocket serverSocket = null;
SSLServer() throws IOException {
// 通過套接字工廠,獲取一個服務(wù)器端套接字
SSLServerSocketFactory socketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket) socketFactory.createServerSocket(SEV_PORT);
}
public void run() {
while (!interrupted()) {
try {
System.out.println("Waiting for connection...");
// 服務(wù)器端套接字進入阻塞狀態(tài),等待來自客戶端的連接請求
SSLSocket socket = (SSLSocket) serverSocket.accept();
// 獲取服務(wù)器端套接字輸入流
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 從輸入流中讀取客戶端用戶名和密碼
String userName = input.readLine();
String password = input.readLine();
// 獲取服務(wù)器端套接字輸出流
PrintWriter output = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream()));
// 對請求進行認證,如果通過則將保密內(nèi)容發(fā)送給客戶端
if (userName.equals(USER_NAME) && password.equals(PASSWORD)) {
output.println("Welcome, " + userName);
output.println(SECRET_CONTENT);
} else {
output.println("Authentication failed, you have no access to the content...");
}
// 關(guān)閉流資源和套接字資源
output.close();
input.close();
socket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
private static class SSLClient {
private SSLSocket socket = null;
SSLClient() throws IOException {
// 通過套接字工廠,獲取一個客戶端套接字
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
socket = (SSLSocket) socketFactory.createSocket("localhost", SEV_PORT);
}
void connect() {
try {
// 獲取客戶端套接字輸出流
PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
// 將用戶名和密碼通過輸出流發(fā)送到服務(wù)器端
output.println(USER_NAME);
output.println(PASSWORD);
output.flush();
// 獲取客戶端套接字輸入流
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 從輸入流中讀取服務(wù)器端傳送的數(shù)據(jù)內(nèi)容,并打印出來
String response = input.readLine();
response += "\n " + input.readLine();
System.out.println(response);
// 關(guān)閉流資源和套接字資源
output.close();
input.close();
socket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
參考
https://www.ibm.com/developerworks/cn/java/j-lo-ssltls/index.html
https://zhuanlan.zhihu.com/p/66029254
https://blog.csdn.net/CrazyMo_/article/details/89137739
http://www.itdecent.cn/p/66dcc049ff32
http://www.itdecent.cn/p/81efc02b2f29