当前位置: 欣欣网 > 码农

既然有了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