當前位置: 妍妍網 > 碼農

既然有了HTTP,為什麽還要HTTPS?

2024-07-11碼農

在當今的互聯網時代,資訊傳播的速度和互動的便捷性為我們的生活帶來了極大的便利。然而,隨之而來的數據安全與個人私密保護問題也變得尤為緊迫。在這樣的背景下,HTTPS協定的普及已成為大勢所趨。

與傳統的HTTP相比,HTTPS在網站地址字首的使用,為使用者與網站之間構建了一道堅固的安全螢幕障。本文將從安全性、信任度、合規性、效能及未來發展等多個方面,深入探討為什麽越來越多的網站選擇以HTTPS開頭,而不是HTTP。

一、HTTPS相較於HTTP有哪些優勢?

1、安全性:加密傳輸以抵禦數據竊聽

超文本傳輸協定(HTTP)是互聯網中最廣泛使用的協定之一,其主要工作方式是明文傳輸數據,這使得數據在傳輸過程中容易被監聽、截取和篡改。這種情況在處理如使用者名稱、密碼和信用卡號等敏感資訊時,構成了嚴重的安全風險。

相比之下,HTTPS協定透過在HTTP上增加SSL/TLS加密,保障了數據在傳輸過程中的安全。SSL/TLS協定利用公鑰和私鑰的非對稱加密技術,以及會話金鑰的對稱加密技術,為封包提供了強有力的加密保護。

2、身份驗證:確保網站真實以防止釣魚欺詐

HTTPS不僅提供數據加密,還包含重要的身份驗證功能。網站在啟用HTTPS時,必須從權威的證書頒發機構(CA)獲取SSL證書。該證書包含了網站的身份資訊並經過數位簽名,確保使用者存取的網站是真實可信的,而非假冒站點。

3、搜尋引擎最佳化與使用者體驗

使用HTTPS的網站在搜尋結果中的排名可能會優於HTTP網站。這不僅提升了網站的安全性,還間接提高了網站的搜尋引擎可見度,吸引更多流量。

4、效能最佳化與未來趨勢

過去,由於加密過程可能導致頁面載入速度減慢,HTTPS被視為影響效能的因素。但隨著技術的進步,如HTTP/2、HTTP/3協定的引入以及TLS 1.3的高效加密演算法,HTTPS的效能劣勢已大大縮小。甚至在某些情況下,得益於協定最佳化和瀏覽器預載入機制,HTTPS的效能表現優於HTTP。

綜上所述,網站選擇以HTTPS開頭而非HTTP,是互聯網發展至今的必然結果。HTTPS不僅確保數據安全傳輸,還在構建信任、最佳化搜尋引擎排名、符合法規要求、提升使用者體驗以及適應技術發展趨勢等方面具有重要意義。

下面就從程式碼實戰方向,詳述一下Java中如何實作HTTPS伺服端、客戶端、簽名證書。

二、生成自簽名證書

開啟命令列工具(CMD 或終端),執行以下命令生成自簽名證書:

keytool -genkeypair -aliastest -keyalg RSA -keysize 2048 -validity 365 -storetype PKCS12 -keystore test.p12 -storepass password

1、該命令的各個參數說明如下:

  • -genkeypair :生成金鑰對(公鑰和私鑰)。

  • -alias test :金鑰對的別名為 test

  • -keyalg RSA :金鑰演算法為 RSA。

  • -keysize 2048 :金鑰大小為 2048 位。

  • -validity 365 :證書有效期為 365 天。

  • -storetype PKCS12 :金鑰庫型別為 PKCS12。

  • -keystore test.p12 :金鑰庫檔名為 test.p12

  • -storepass password :金鑰庫密碼為 password

  • 在執行上述命令時,您會被提示輸入一些資訊,如下:

    What is your first and last name?
    [Unknown]: Your Name
    What is the name of your organizational unit?
    [Unknown]: Your Organizational Unit
    What is the name of your organization?
    [Unknown]: Your Organization
    What is the name of your City or Locality?
    [Unknown]: Your City
    What is the name of your State or Province?
    [Unknown]: Your State
    What is the two-letter country code for this unit?
    [Unknown]: US
    Is CN=Your Name, OU=Your Organizational Unit, O=Your Organization, L=Your City, ST=Your State, C=US correct?
    [no]: yes

    按照提示輸入相關資訊,完成後自簽名證書將生成在 test.p12 檔中。

    2、解決報錯:執行命令之後,keytool 錯誤: java.io.IOException: toDerInputStream rejects tag type 107

    這個錯誤通常表示金鑰庫檔格式或其內容有問題。以下是一些可能的解決方案:

    1. 檢查 keytool 命令和參數 :確保您使用了正確的命令和參數來生成金鑰庫檔。

    2. 嘗試不同的金鑰庫格式 :嘗試使用 JKS(Java KeyStore)格式而不是 PKCS12。雖然 PKCS12 是更現代的標準,但是 JKS 在某些情況下可能更相容。

    3. 確保環境變量正確 :確保您的環境變量和 keytool 版本正確,尤其是如果您有多個 Java 安裝。

    3、自動填寫資訊

    如果不想每次都手動輸入這些資訊,可以在命令中使用 -dname 參數指定這些資訊。例如:

    keytool -genkeypair -aliastest -keyalg RSA -keysize 2048 -validity 365 -keystore test.p12 -storetype PKCS12 -storepass password -dname "CN=Your Name, OU=Your Organizational Unit, O=Your Organization, L=Your City, ST=Your State, C=CN"

    4、解決報錯:執行之後報錯,keytool 錯誤: java.lang.Exception: 金鑰庫檔存在, 但為空: test.p12

    這個錯誤表明 test.p12 檔已經存在,但其中沒有內容。可能是在之前的嘗試中建立了這個檔,但沒有成功寫入任何數據。以下是解決方案:

    刪除現有的空檔並重新生成

    不需要在執行 keytool 命令之前手動建立 test.p12 檔。 keytool 命令會自動生成並建立這個檔。如果 test.p12 檔已經存在, keytool 會更新這個檔中的金鑰對和證書。

    刪除檔後,提示我keytool 錯誤: java.io.FileNotFoundException: test.p12 (拒絕存取。)

    確認當前使用者有許可權

    確保當前使用者對相關目錄和檔具有讀寫許可權。如果您在 Windows 上執行命令提示字元或在 Unix/Linux 系統上執行終端,嘗試使用管理員許可權。

    Windows 系統

    1. 以管理員身份執行命令提示字元

  • 右鍵點選「命令提示字元」,選擇「以管理員身份執行」。

  • 確認檔是否存在並刪除

  • Unix/Linux 系統

    以超級使用者身份執行終端

  • 使用 sudo 提升許可權:```sudo rm test.p12`1``

  • 總結步驟

    1. 以管理員許可權執行命令提示字元或終端

    2. 刪除空的 test.p12

    3. 確保當前使用者對目錄具有寫許可權

    4. 重新生成自簽名證書

    三、範例程式碼

    1、本地 HTTPS 伺服器

    在生成了自簽名證書之後,可以將其用於您的 HTTPS 伺服器配置中。

    使用生成的自簽名證書配置一個本地 HTTPS 伺服器。

    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpHandler;
    import com.sun.net.httpserver.HttpsConfigurator;
    import com.sun.net.httpserver.HttpsServer;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetSocketAddress;
    import java.security.KeyStore;
    public classLocalHttpsServer{
    publicstaticvoidmain(String[] args)throws Exception {
    // 載入金鑰庫
    char[] passphrase = "password".toCharArray();
    KeyStore ks = KeyStore.getInstance("PKCS12");
    ks.load(new FileInputStream("C:\\Program Files\\Java\\jdk1.8.0_60\\bin\\test.p12"), passphrase);
    // 初始化金鑰管理器工廠
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, passphrase);
    // 初始化信任管理器工廠
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(ks);
    // 初始化 SSL 上下文
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    // 建立 HTTPS 伺服器
    HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress(8443), 0);
    httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
    // 建立處理器
    httpsServer.createContext("/api"new HttpHandler() {
    @Override
    publicvoidhandle(HttpExchange exchange){
    try {
    if ("POST".equals(exchange.getRequestMethod()) && "application/json".equals(exchange.getRequestHeaders().getFirst("Content-Type"))) {
    InputStream is = exchange.getRequestBody();
    StringBuilder jsonString = new StringBuilder();
    int i;
    while ((i = is.read()) != -1) {
    jsonString.append((char) i);
    }
    System.out.println("Received JSON: " + jsonString.toString());
    String response = "{\"message\":\"Received\"}";
    exchange.getResponseHeaders().set("Content-Type""application/json");
    exchange.sendResponseHeaders(200, response.getBytes().length);
    OutputStream os = exchange.getResponseBody();
    os.write(response.getBytes());
    os.close();
    else {
    exchange.sendResponseHeaders(405, -1); // Method Not Allowed
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    });
    // 啟動伺服器
    httpsServer.setExecutor(null);
    httpsServer.start();
    System.out.println("HTTPS server started at https://localhost:8443/api");
    }
    }








    2、測試 HTTPS 伺服器

    建立好 HTTPS 伺服器後,您可以使用以下 Java 客戶端進行測試:

    import javax.net.ssl.*;
    import java.io.OutputStream;
    import java.io.InputStream;
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.URL;
    import java.security.cert.X509Certificate;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    public classHttpsPostJsonClient{
    publicstaticvoidmain(String[] args){
    String httpsURL = "https://localhost:8443/api";
    String jsonInputString = "{\"param1\":\"value1\",\"param2\":\"value2\"}";
    try {
    // 信任所有證書
    TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers() { returnnull; }
    publicvoidcheckClientTrusted(X509Certificate[] certs, String authType){ }
    publicvoidcheckServerTrusted(X509Certificate[] certs, String authType){ }
    }
    };
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    publicbooleanverify(String hostname, javax.net.ssl.SSLSession sslSession){
    returntrue;
    }
    });
    // 建立 URL 物件
    URL url = new URL(httpsURL);
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    // 設定請求方法為 POST
    connection.setRequestMethod("POST");
    // 允許寫入和讀取數據
    connection.setDoOutput(true);
    connection.setDoInput(true);
    // 設定請求頭
    connection.setRequestProperty("Content-Type""application/json");
    connection.setRequestProperty("Accept""application/json");
    // 發送 POST 數據
    try (OutputStream os = connection.getOutputStream()) {
    byte[] input = jsonInputString.getBytes("UTF-8");
    os.write(input, 0, input.length);
    }
    // 讀取響應
    try (InputStream is = connection.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
    StringBuilder response = new StringBuilder();
    String responseLine;
    while ((responseLine = br.readLine()) != null) {
    response.append(responseLine.trim());
    }
    System.out.println("Response: " + response.toString());
    }
    catch (Exception e) {
    System.out.println("exception===: " + e);
    }
    }
    }








    3、測試

    (1)透過curl 命令列測試

    curl -X POST https://localhost:8443/api -H "Content-Type: application/json" -d '{"param1":"value1","param2":"value2"}' -k

    (2)透過客戶端程式碼測試

    透過上述步驟,您可以生成自簽名證書,並使用 Java 建立一個本地 HTTPS 伺服器,接收 application/json 的 POST 請求,並透過 Java 客戶端進行測試。

    4、解決報錯:透過你的測試伺服器程式碼存取之後報錯,java.io.IOException: Server returned HTTP response code: 405 for URL: https://localhost:8443/api

    HTTP 405 錯誤表示 "Method Not Allowed",即伺服器端拒絕了請求方法。由於我們在範例中設定了伺服器僅接受 POST 請求,如果客戶端發送了其他方法(例如 GET),伺服器會返回 405 錯誤。

    我們需要確保客戶端程式碼確實發送了 POST 請求,並且伺服器端處理常式正確設定。

    我是因為設定請求頭時,寫的 connection.setRequestProperty("Content-Type", "application/json; utf-8"); ,將其改為 connection.setRequestProperty("Content-Type", "application/json"); 就解決了。

    ·················END·················

    國內直接使用ChatGPT4o

    1. 無需魔法,同時支持手機、電腦,瀏覽器直接使用

    2. 帳號獨享

    3. ChatGPT3.5永久免費

    長按辨識下方二維碼,備註ai,發給你

    回復gpt,獲取ChatGPT4o直接使用地址

    點選閱讀原文,國內直接使用ChatGpt4o