SSL/TCL

概念

  • 安全套接層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ù)在傳輸過程中不被改變。

工作原理

  1. 通過CA體系交換public key
  2. 通過非對稱加密算法,交換用于對稱加密的密鑰
  3. 通過對稱加密算法,加密正常的網(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)或者瀏覽器中的。

工作流程

image.png

步驟 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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容