通过 WiFi 使用 HTTPS 传输数据



在上一章中,我们研究了如何使用 ESP32 通过 HTTP 传输数据。在本章中,我们将通过 HTTPS 传输数据。HTTPS 中的 S 代表“安全”。基本上,您传输的任何数据都使用传输层安全性 (TLS) 进行加密。这意味着,如果有人窃听您的通信,他们将无法理解您传输的内容。相反,他们得到的是一些乱码。本章不涉及 HTTPS 的工作原理。但简单的 Google 搜索将为您提供多个有用的资源以帮助您入门。在本章中,我们将了解如何在 ESP32 上实现 HTTPS。

将任何 HTTP 请求转换为 ESP32 上的 HTTPS

通常,如果您有用于向服务器发送 HTTP 请求的代码,则可以通过以下简单步骤将其转换为 HTTPS:

  • 将库从 WiFiClient 更改为 WiFiClientSecure(您需要包含 WiFiClientSecure.h)

  • 将端口从 80 更改为 443

还有一个可选的第四步:为服务器添加 CA 证书。此步骤是可选的,因为它不会影响通信的安全性。它只是确保您正在与正确的服务器通信。如果您不提供 CA 证书,您的通信仍然是安全的。

代码演练

您在下面看到的代码与用于 HTTP 通信的代码非常相似。强烈建议您重新访问那一章。在本演练中,我们将仅重点介绍与 HTTP 代码不同的部分。

代码可以在 GitHub 上找到

我们首先包含 WiFi 库。我们还需要在此处包含 WiFiClientSecure 库。

#include <WiFi.h>
#include <WiFiClientSecure.h>

接下来,我们将定义常量。请注意,端口现在为 443 而不是 80。

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

const char* server = "httpbin.org";
const int port = 443;

接下来,我们创建 WiFiClientSecure 对象,而不是 WiFiClient 对象。

WiFiClientSecure client;

接下来,我们为我们的服务器 (httpbin.org) 定义 CA 证书。现在,您可能想知道如何获取我们服务器的 CA 证书。此处提供了使用 Google Chrome 获取任何服务器的 CA 证书的详细步骤。在同一篇文章中,还提供了一篇关于 CA 证书有效性的说明,建议使用认证机构的证书,而不是服务器的证书,尤其是在您只需编程设备一次并将其发送到现场多年使用的应用程序中。认证机构的证书具有更长的有效期(15年以上),而服务器的证书有效期较短(1-2年)。因此,我们使用 Starfield Class 2 认证机构的证书(有效期至 2034 年),而不是 httpbin.org 的证书(有效期至 2021 年 2 月)。

CA Certificate
const char* ca_cert = \ 
"-----BEGIN CERTIFICATE-----\n" \
"MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"\
"MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"\
"U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"\
"NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"\
"ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"\
"ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"\
"DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"\
"8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"\
"+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"\
"X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"\
"K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"\
"1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"\
"A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"\
"zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"\
"YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"\
"bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"\
"DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"\
"L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"\
"eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"\
"xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"\
"VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"\
"WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"\
"-----END CERTIFICATE-----\n";

在设置中,我们像以前一样使用提供的凭据以 station 模式连接到 WiFi。在这里,我们还有设置 WiFiSecureClient 的 CA 证书的额外步骤。通过这样做,我们告诉客户端只有当其 CA 证书与提供的证书匹配时才与服务器通信。

void setup() {
   Serial.begin(115200);
   WiFi.mode(WIFI_STA);                    //The WiFi is in station mode. The    other is the softAP mode
   WiFi.begin(ssid, password);
   while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
   }
   Serial.println("");  Serial.print("WiFi connected to: "); Serial.println(ssid);  Serial.println("IP address: ");  Serial.println(WiFi.localIP());
   client.setCACert(ca_cert);            //Only communicate with the server if the CA certificates match
   delay(2000);
}

循环与 HTTP 示例中使用的循环完全相同。

void loop() {
   int  conn;
   int chip_id = ESP.getEfuseMac();;
   Serial.printf("  Flash Chip id = %08X\t", chip_id);
   Serial.println();
   Serial.println();
   String body = "ChipId=" + String(chip_id) + "&SentBy=" + "your_name";
   int body_len = body.length();

   Serial.println(".....");
   Serial.println(); Serial.print("For sending parameters, connecting to "); Serial.println(server);
   conn = client.connect(server, port);

   if (conn == 1) {
      Serial.println(); Serial.print("Sending Parameters...");
      //Request
      client.println("POST /post HTTP/1.1");
      //Headers
      client.print("Host: "); client.println(server);
      client.println("Content-Type: application/x−www−form−urlencoded");
      client.print("Content-Length: "); client.println(body_len);
      client.println("Connection: Close");
      client.println();
      //Body
      client.println(body);
      client.println();

      //Wait for server response
      while (client.available() == 0);

      //Print Server Response
      while (client.available()) {
         char c = client.read();
         Serial.write(c);
      }
   } else {
      client.stop();
      Serial.println("Connection Failed");
   }
   delay(5000);
}

服务器期望的响应也类似于 HTTP 示例。唯一的区别是收到的响应也将是安全的。但我们不必担心解密加密的消息。ESP32 为我们完成了这项工作。

HTTPS Server response

请注意服务器响应中的 URL 字段。它包含 https 而不是 http,确认我们的传输是安全的。事实上,如果您稍微编辑 CA 证书,例如删除一个字符,然后尝试运行草图,您将看到连接失败。

HTTPS Server Failed Connection

但是,如果您从设置中删除了client.setCACert()行,即使使用有故障的 CA 证书,连接也将再次安全地建立。这证明设置 CA 证书不会影响我们通信的安全性。它只是帮助我们验证我们正在与正确的服务器通信。如果我们确实设置了证书,那么 ESP32 只有在提供的 CA 证书与服务器的 CA 证书匹配时才会与服务器通信。如果我们不设置证书,ESP32 仍然可以安全地与服务器通信。

恭喜!!您已成功使用 ESP32 发送 HTTPS 请求。

注意 - ESP32 上执行 HTTPS 消息加密的硬件加速器最多支持 16384 字节(16 KB)的数据。因此,如果您的消息大小超过 16 KB,您可能需要将其分解成块。

参考文献

广告