ESP8266 NodeMCU: HTTPS-запросы (Arduino IDE)

В этом руководстве вы узнаете, как выполнять HTTPS-запросы с помощью платы ESP8266 NodeMCU. Мы познакомим вас с некоторыми фундаментальными концепциями HTTPS и предоставим несколько примеров: HTTPS-запросы без сертификата, с отпечатком и с сертификатом.

ESP8266 NodeMCU HTTPS-запросы Arduino IDE Core

У нас есть аналогичное руководство для платы ESP32:

Содержание статьи

В этой статье мы рассмотрим следующие темы:

Введение

Чтобы понять, как выполнять HTTPS-запросы с помощью ESP8266, лучше быть знакомым с некоторыми фундаментальными концепциями, которые мы объясним далее. Мы также рекомендуем ознакомиться со следующей статьёй:

Что такое HTTPS?

HTTPS — это защищённая версия протокола HTTP, отсюда и буква «S», которая означает «secure» (безопасный).

HTTP — это протокол для передачи данных через интернет. Когда эти данные зашифрованы с помощью SSL/TLS, это называется HTTPS.

Протокол HTTP vs HTTPS

Проще говоря, HTTPS — это тот же протокол HTTP, но с данными, зашифрованными с помощью SSL/TLS.

Зачем нужен HTTPS на ESP8266?

Использование HTTPS обеспечивает следующее:

1) Шифрование: весь трафик между ESP8266 и сервером будет зашифрован — никто не сможет подсмотреть ваши запросы и пароли, они увидят только бессмысленный набор символов.

ESP8266 HTTPS-запросы зашифрованная связь

При использовании библиотек ESP8266 для выполнения HTTPS-запросов они берут на себя шифрование и дешифрование сообщений.

2) Доверие к серверу (идентификация): при использовании HTTPS через сертификаты TLS/SSL вы гарантируете, что подключены к тому серверу, к которому ожидали — то есть вы всегда знаете, к кому подключены.

SSL/TLS сертификат действительный

Чтобы убедиться, что мы подключены к правильному серверу, нам нужно проверить сертификат сервера на ESP8266 или отпечаток сервера. Это означает, что нам нужно скачать сертификат сервера или отпечаток и жёстко прописать его в нашем скетче, чтобы мы могли проверить, действительно ли мы подключены к тому серверу, к которому ожидаем.

Сертификаты SSL/TLS

SSL-сертификаты выдаются легитимными центрами сертификации (Certificate Authorities). Один из самых известных — LetsEncrypt. Центры сертификации подтверждают личность владельца сертификата и предоставляют доказательство того, что сертификат действителен. Сертификат также содержит открытый ключ сервера для асимметрично зашифрованной связи с клиентом.

TLS SSL сертификат публичный ключ

Когда центр сертификации выдаёт сертификат, он подписывает его своим корневым сертификатом. Этот корневой сертификат должен находиться в базе данных доверенных сертификатов, называемой хранилищем корневых сертификатов (root store). Ваш браузер и операционная система содержат базу данных корневых сертификатов, которым они могут доверять (хранилище корневых сертификатов). На следующем скриншоте показаны некоторые доверенные корневые сертификаты.

Доверенные корневые сертификаты Chrome

Итак, когда вы подключаетесь к веб-сайту через браузер, он проверяет, был ли его сертификат подписан корневым сертификатом, принадлежащим его хранилищу корневых сертификатов. Новые корневые сертификаты добавляются или удаляются из хранилища корневых сертификатов с каждым обновлением браузера.

Клиент-серверные TLS SSL сертификаты

Когда вы используете ESP8266, вам нужно загрузить сертификаты, которым вы доверяете, на вашу плату. Обычно вы добавляете только сертификат для сервера, к которому хотите подключиться.

ESP8266 проверка сертификата сервера для безопасного подключения

Но также возможно загрузить хранилище корневых сертификатов на вашу плату, чтобы иметь больше вариантов и не беспокоиться о поиске сертификата конкретного веб-сайта.

Цепочка сертификатов

SSL-сертификат является частью цепочки SSL-сертификатов. Что такое цепочка сертификатов?

Цепочка сертификатов включает следующее:

  • корневой сертификат (от центра сертификации);

  • один или несколько промежуточных сертификатов;

  • сертификат сервера.

Сертификат сервера — это то, что заставляет ваш браузер отображать значок безопасного замка при посещении веб-сайта. Это означает, что у сервера есть действительный SSL/TLS-сертификат и все соединения с веб-сайтом зашифрованы. Действительный SSL/TLS-сертификат — это сертификат, которому доверяет ваш браузер. Что делает его доверенным?

Как мы упоминали ранее, SSL/TLS-сертификаты выдаются центрами сертификации. Однако эти центры не выдают сертификаты напрямую веб-сайтам. Они используют промежуточные сертификаты, которые выдают сертификат сервера (Центр сертификации > промежуточный сертификат > сертификат сервера). На следующем скриншоте показан пример для веб-сайта Github. Вы можете видеть иерархию сертификатов, выделенную красным прямоугольником.

Цепочка SSL-сертификатов иерархия

Ваш браузер проверяет эту цепочку сертификатов, пока не найдёт корневой сертификат. Если этот сертификат находится в хранилище корневых сертификатов браузера, то он считает сертификат действительным. В данном случае DigiCert Global Root CA находится в хранилище корневых сертификатов браузера. Поэтому в строке браузера отображается значок «безопасно».

Значок безопасности Github

Следующая диаграмма показывает общее представление о том, как это работает.

Пример цепочки сертификатов

Итого:

  • Корневой сертификат: это самоподписанный сертификат, выданный центром сертификации. Закрытый ключ этого сертификата используется для подписи следующего сертификата в иерархии сертификатов. Корневые сертификаты загружаются в хранилища доверия браузеров и операционных систем.

  • Промежуточный сертификат: он подписан закрытым ключом корневого сертификата. Открытый ключ промежуточного сертификата — это тот, который подписывает сертификат сервера. Промежуточных сертификатов может быть более одного.

  • Сертификат сервера: этот сертификат выдаётся для конкретного доменного имени на сервере. Он подписан открытым ключом промежуточного сертификата. Если он действителен (доверенная цепочка сертификатов), браузер отображает значок безопасного замка в строке поиска рядом с доменом веб-сайта.

На ESP8266, чтобы проверить подлинность сервера, вы можете загрузить любой из этих сертификатов: корневой, промежуточный или сертификат сервера. Вместо сертификата вы также можете проверить отпечаток сертификата. Отпечаток — это хеш сертификата (уникальный идентификатор сертификата, сгенерированный из информации сертификата).

Срок действия сертификатов

SSL/TLS-сертификаты имеют срок действия. Вы можете проверить в браузере дату истечения срока действия сертификата для конкретного сервера. Сертификат сервера обычно имеет короткий срок действия, а срок действия отпечатка ещё короче.

Поэтому, если вы хотите использовать их в своих проектах на ESP8266, вам придётся довольно часто обновлять свой код. Если вы хотите, чтобы ваш код работал годами без забот, вы можете использовать корневой сертификат веб-сайта, который обычно действителен от пяти до десяти лет или более. Однако использование отпечатка может быть полезно для целей тестирования или может быть хорошим вариантом в зависимости от приложения.

Получение сертификата сервера

Существуют разные способы получить сертификат сервера. Один из самых простых способов — скачать сертификат напрямую из вашего браузера. Вы также можете использовать OpenSSL и получить всю необходимую информацию о сертификате с помощью командной строки (мы не будем рассматривать этот метод в данном руководстве).

В этом разделе вы узнаете, как получить сертификат сервера. Мы обычно будем использовать корневой сертификат, но вы можете использовать любой другой сертификат из цепочки сертификатов — вам просто нужно помнить о сроке действия сертификата.

Получение сертификата сервера с помощью Google Chrome

В этом разделе мы покажем, как получить сертификат сервера с помощью Google Chrome (это веб-браузер, который мы используем чаще всего). Инструкции для других веб-браузеров должны быть аналогичными.

Примеры, которые мы будем использовать позже, показывают, как выполнить HTTPS-запрос к веб-сайту howmyssl.com. Поэтому, для демонстрации, мы покажем вам, как получить его корневой сертификат. Процедура аналогична для других веб-сайтов.

Как получить сертификат веб-сайта с помощью Google Chrome?

  1. Перейдите на веб-сайт, для которого вы хотите получить сертификат.

  2. Нажмите на значок замка, а затем нажмите на Show connection details (Показать информацию о подключении).

Google Chrome сертификат веб-сайта SSL
  1. Затем нажмите на Show certificate (Показать сертификат).

Google Chrome информация о сертификате веб-сайта SSL
  1. Откроется новое окно со всей информацией о сертификате веб-сайта. Нажмите на вкладку Details (Подробности), убедитесь, что выбран корневой сертификат (это то, что мы ищем в этом примере), затем нажмите Export… (Экспорт…).

Google Chrome подробности сертификата веб-сайта SSL
  1. Выберите место на вашем компьютере для сохранения сертификата. Сохраните его в формате по умолчанию: Base64-encoded ASCII, single certificate (*.pem, .crt). И это всё.

Вы можете дважды щёлкнуть по файлу сертификата, чтобы проверить его подробности, включая дату истечения срока действия.

Google Chrome информация о SSL-сертификате расширенная

Откройте сертификат с помощью Блокнота или другого аналогичного программного обеспечения. Вы должны получить что-то похожее на то, что показано ниже.

SSL-сертификат в блокноте

Как получить отпечаток веб-сайта с помощью Google Chrome?

Получение отпечатка сертификата веб-сайта — простой процесс. Следуйте следующим инструкциям:

  1. Перейдите на веб-сайт, для которого вы хотите получить отпечаток.

  2. Нажмите на значок замка, а затем нажмите на Show connection details (Показать информацию о подключении).

Google Chrome сертификат веб-сайта SSL
  1. Затем нажмите на Show certificate (Показать сертификат).

Google Chrome информация о сертификате веб-сайта SSL — сертификат действителен
  1. Откроется новое окно со всей информацией о сертификате веб-сайта, включая отпечатки. Для примеров ESP8266 вы будете использовать отпечаток SHA-1.

Пример отпечатка веб-сайта

HTTPS-запросы на ESP8266 NodeMCU

Теперь, когда вы знаете все основные важные аспекты сертификатов и как получить сертификат сервера, давайте наконец посмотрим, как выполнять HTTPS-запросы с помощью ESP8266, используя ядро Arduino. Мы рассмотрим разные методы: без сертификата, с отпечатком веб-сайта и с корневым сертификатом сервера.

HTTPS-запросы на плате ESP8266 NodeMCU

Вы можете найти различные примеры, показывающие, как выполнять HTTPS-запросы с ESP8266, в разделе примеров Arduino IDE.

  • Basic HTTPS Client (библиотека ESP8266HTTPClient): File > Examples > ESP8266HTTPClient > `BasicHTTPSClient <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino>`_

  • Basic HTTPS Client (библиотека WiFiClientSecure): File > Examples > ESP8266WiFi > `HTTPSRequest <https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WiFi/examples/HTTPSRequest>`_

Вам нужно будет обновить сертификаты и отпечатки, чтобы примеры работали. Мы создали несколько примеров на основе этих. Все представленные примеры выполняют запрос к веб-сайту www.howsmyssl.com/a/check. Он возвращает некоторую информацию о том, насколько безопасно HTTPS-соединение. Давайте рассмотрим их.

ESP8266 NodeMCU HTTPS-запросы – без сертификата

Вы можете выполнять HTTPS-запросы с ESP8266 без сертификата и без отпечатка. Соединение будет зашифровано, но вы пропустите проверку SSL-сертификата сервера. Это означает, что вы не будете уверены, является ли сервер, к которому вы подключены, действительно тем, за кого он себя выдаёт. Эта ситуация полезна для целей тестирования или для выполнения HTTPS-запросов к локальным серверам внутри вашей сети.

Следующий код основан на примере BasicHttpsClient.

Чтобы протестировать код, просто вставьте ваши сетевые учётные данные и загрузите код на вашу плату.

/*
  Complete project details: https://RandomNerdTutorials.com/esp8266-nodemcu-https-requests/
  Based on the BasicHTTPSClient.ino Created on: 20.08.2018 (ESP8266 examples)
*/

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

void setup() {
  Serial.begin(115200);
  //Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.println();

  //Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
}

void loop() {
  // wait for WiFi connection
  if ((WiFi.status() == WL_CONNECTED)) {

    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);

    // Ignore SSL certificate validation
    client->setInsecure();

    //create an HTTPClient instance
    HTTPClient https;

    //Initializing an HTTPS communication using the secure client
    Serial.print("[HTTPS] begin...\n");
    if (https.begin(*client, "https://www.howsmyssl.com/a/check")) {  // HTTPS
      Serial.print("[HTTPS] GET...\n");
      // start connection and send HTTP header
      int httpCode = https.GET();
      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = https.getString();
          Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
      }

      https.end();
    } else {
      Serial.printf("[HTTPS] Unable to connect\n");
    }
  }
  Serial.println();
  Serial.println("Waiting 2min before the next round...");
  delay(120000);
}

Просмотреть исходный код

Как работает код?

Сначала вам нужно подключить необходимые библиотеки. Вам нужна библиотека WiFiClientSecureBearSSL для выполнения HTTPS-запросов.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>

Вставьте ваши сетевые учётные данные в следующие строки.

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

В setup() инициализируем монитор порта и подключаем плату к вашей Wi-Fi сети.

void setup() {
  Serial.begin(115200);
  // Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.println();

  //Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }

Следующая строка создаёт новый экземпляр WiFiClientSecure под названием client.

std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);

В случае, если вы не хотите проверять сертификат сервера, используйте метод setInsecure() на клиенте.

// Ignore SSL certificate validation
client->setInsecure();

Создаём экземпляр HTTPClient под названием https.

//create an HTTPClient instance
HTTPClient https;

Инициализируем https-клиент на указанном хосте с помощью метода begin(). В данном случае мы выполняем запрос по следующему URL: https://www.howsmyssl.com/a/check.

if (https.begin(*client, "https://www.howsmyssl.com/a/check")) {  // HTTPS

Получаем код ответа сервера.

int httpCode = https.GET();

Если код ответа — положительное число, это означает, что соединение было успешно установлено, поэтому мы можем прочитать полезную нагрузку ответа с помощью метода getString() объекта https. Затем мы можем вывести полезную нагрузку в мониторе порта. В практическом приложении вы можете выполнить любую задачу, которая вам нужна, с ESP8266 в зависимости от полученной полезной нагрузки.

if (https.begin(*client, "https://www.howsmyssl.com/a/check")) {  // HTTPS
  Serial.print("[HTTPS] GET...\n");
  // start connection and send HTTP header
  int httpCode = https.GET();
  // httpCode will be negative on error
  if (httpCode > 0) {
    // HTTP header has been send and Server response header has been handled
    Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
    // file found at server
    if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
      String payload = https.getString();
      Serial.println(payload);
    }

Если код ответа — отрицательное число, это означает, что произошла ошибка. Мы выведем код ошибки.

else {
   Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}

Наконец, закрываем HTTPS-соединение с помощью метода end():

https.end();

Этот конкретный пример выполняет запрос каждые две минуты. Вы должны изменить это в зависимости от требований вашего проекта.

Serial.println("Waiting 2min before the next round...");
delay(120000);

Демонстрация

После загрузки кода откройте монитор порта на скорости 115200 бод. Нажмите встроенную кнопку RST, чтобы начать выполнение вновь загруженного кода.

Вы должны получить что-то похожее на то, что показано на рисунке ниже.

ESP8266 HTTPS пример демонстрация монитор порта

Вы получаете код ответа 200, что означает, что с запросом всё в порядке.

Если вы прокрутите вправо, вы получите результат того, насколько безопасно соединение. Вы должны получить «Probably Okay».

ESP8266 HTTPS пример демонстрация монитор порта результат

Ваше соединение по-прежнему зашифровано, но в этом примере проверка SSL будет пропущена.

ESP8266 NodeMCU HTTPS-запросы – отпечаток

Вы можете выполнять HTTPS-запросы с ESP8266 и проверять подлинность сервера, используя отпечаток сервера. Один из самых больших недостатков использования отпечатка заключается в том, что его срок действия обычно довольно короткий. Поэтому вам придётся довольно часто обновлять свой скетч.

Вот пример с использованием проверки сервера по отпечатку. Этот пример основан на примере BasicHttpsClient. Поскольку отпечаток меняется довольно часто, вам может потребоваться изменить код с текущим отпечатком веб-сайта — смотрите этот раздел, чтобы узнать, как получить отпечаток.

/*
  Complete project details: https://RandomNerdTutorials.com/esp8266-nodemcu-https-requests/
  Based on the BasicHTTPSClient.ino Created on: 20.08.2018 (ESP8266 examples)
*/

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Fingerprint (might need to be updated)
const uint8_t fingerprint[20] = {0x76, 0x99, 0x2e, 0x6f, 0x04, 0xf4, 0xad, 0x19, 0xba, 0x54, 0xf5, 0x92, 0x50, 0x51, 0x56, 0x2b, 0x86, 0x8b, 0x5a, 0x92};

void setup() {
  Serial.begin(115200);
  //Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.println();

  //Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
}

void loop() {
  // wait for WiFi connection
  if ((WiFi.status() == WL_CONNECTED)) {

    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);

    client->setFingerprint(fingerprint);
    // Or, if you happy to ignore the SSL certificate, then use the following line instead:
    // client->setInsecure();

    HTTPClient https;

    Serial.print("[HTTPS] begin...\n");
    if (https.begin(*client, "https://www.howsmyssl.com/a/check")) {  // HTTPS

      Serial.print("[HTTPS] GET...\n");
      // start connection and send HTTP header
      int httpCode = https.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);

        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = https.getString();
          Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
      }

      https.end();
    } else {
      Serial.printf("[HTTPS] Unable to connect\n");
    }
  }

  Serial.println();
  Serial.println("Waiting 2min before the next round...");
  delay(120000);
}

Просмотреть исходный код

Как работает код?

Код в этом примере очень похож на предыдущий, но добавляет необходимые строки для проверки отпечатка сервера. Мы лишь кратко рассмотрим строки, относящиеся к этому примеру. Для более подробного объяснения смотрите предыдущий пример.

Сначала вам нужно подключить необходимые библиотеки. Вам нужна библиотека WiFiClientSecureBearSSL для выполнения HTTPS-запросов.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>

Вставьте ваши сетевые учётные данные в следующие строки:

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Вставьте отпечаток сервера в следующую строку:

// Fingerprint for demo URL (might need to be updated)
const uint8_t fingerprint[20] = {0x76, 0x99, 0x2e, 0x6f, 0x04, 0xf4, 0xad, 0x19, 0xba, 0x54, 0xf5, 0x92, 0x50, 0x51, 0x56, 0x2b, 0x86, 0x8b, 0x5a, 0x92};

В предыдущем разделе мы видели, что отпечаток для URL, по которому мы будем выполнять запрос:

76 99 2E 6F 04 F4 AD 19 BA 54 F5 92 50 51 56 2B 86 8B 5A 92
Пример отпечатка веб-сайта

Итак, вы должны вставить его в ваш код следующим образом:

const uint8_t fingerprint[20] = {0x76, 0x99, 0x2e, 0x6f, 0x04, 0xf4, 0xad, 0x19, 0xba, 0x54, 0xf5, 0x92, 0x50, 0x51, 0x56, 0x2b, 0x86, 0x8b, 0x5a, 0x92};

Поскольку отпечаток часто меняется, вам может потребоваться перепроверить текущий отпечаток. Если вы выполняете запрос по другому URL, вам нужно получить его отпечаток, как описано ранее.

Вам нужно создать экземпляр WiFiClientSecure под названием client.

std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);

Чтобы установить отпечаток сервера, используйте метод setFingerprint() на клиенте и передайте отпечаток в качестве аргумента:

client->setFingerprint(fingerprint);

Создаём экземпляр HTTPClient под названием https.

//create an HTTPClient instance
HTTPClient https;

Инициализируем https-клиент на указанном хосте с помощью метода begin(). В данном случае мы выполняем запрос по следующему URL: https://www.howsmyssl.com/a/check.

if (https.begin(*client, "https://www.howsmyssl.com/a/check")) {  // HTTPS

Затем вам просто нужно обработать ответ сервера. Код ответа 200 означает, что всё прошло как ожидалось. Код ответа с отрицательным числом означает, что что-то пошло не так с запросом.

 int httpCode = https.GET();

// httpCode will be negative on error
if (httpCode > 0) {
  // HTTP header has been send and Server response header has been handled
  Serial.printf("[HTTPS] GET... code: %d\n", httpCode);

  // file found at server
  if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
    String payload = https.getString();
    Serial.println(payload);
  }
} else {
  Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}

Демонстрация

После загрузки кода откройте монитор порта на скорости 115200 бод. Нажмите встроенную кнопку RST, чтобы начать выполнение вновь загруженного кода.

Вы должны получить что-то похожее на то, что показано на рисунке ниже (точно так же, как в предыдущем примере).

ESP8266 HTTPS пример демонстрация монитор порта

Вы получаете код ответа 200, что означает, что с запросом всё в порядке.

Если вы прокрутите вправо, вы получите результат того, насколько безопасно соединение. Вы должны получить «Probably Okay».

ESP8266 HTTPS пример демонстрация монитор порта результат

Ваше соединение зашифровано, и вы проверили подлинность сервера, используя отпечаток сервера.

ESP8266 NodeMCU HTTPS-запросы – корневой сертификат

В этом разделе мы покажем пример HTTPS-запроса с использованием корневого сертификата сервера.

Использование корневого сертификата сервера — отличный вариант, потому что вы проверяете SSL-сертификат сервера и, таким образом, гарантируете, что общаетесь с правильным сервером. Кроме того, корневой сертификат обычно действителен более пяти лет, что означает, что вам не нужно постоянно обновлять свой скетч ESP8266 (в отличие от метода с отпечатком).

Мы предоставляем пример, основанный на примере ESP8266_HTTPSRequest, который вы можете найти в вашей Arduino IDE: File > Examples > ESP8266WiFi > `HTTPSRequest <https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WiFi/examples/HTTPSRequest>`_.

/*
  Complete project details: https://RandomNerdTutorials.com/esp8266-nodemcu-https-requests/
  Based on the example created by Ivan Grokhotkov, 2015 (File > Examples > ESP8266WiFi > HTTPSRequests)
*/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>

// Root certificate for howsmyssl.com
const char IRG_Root_X1 [] PROGMEM = R"CERT(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)CERT";

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create a list of certificates with the server certificate
X509List cert(IRG_Root_X1);

void setup() {
  Serial.begin(115200);
  //Serial.setDebugOutput(true);

  Serial.println();
  Serial.println();
  Serial.println();

  //Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }

  // Set time via NTP, as required for x.509 validation
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");

  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
}

void loop() {
  WiFiClientSecure client;

  // wait for WiFi connection
  if ((WiFi.status() == WL_CONNECTED)) {

    client.setTrustAnchors(&cert);

    HTTPClient https;

    Serial.print("[HTTPS] begin...\n");
    if (https.begin(client, "https://www.howsmyssl.com/a/check")) {  // HTTPS

      Serial.print("[HTTPS] GET...\n");
      // start connection and send HTTP header
      int httpCode = https.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);

        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = https.getString();
          Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
      }

      https.end();
    } else {
      Serial.printf("[HTTPS] Unable to connect\n");
    }
  }

  Serial.println();
  Serial.println("Waiting 2min before the next round...");
  delay(10000);
}

Просмотреть исходный код

Этот пример делает то же самое, что и предыдущие (выполняет запрос к веб-сайту www.howsmyssl.com), но проверяет сертификат сервера. Вы можете выполнить запрос к любому другому веб-сайту, если у вас есть его сертификат сервера.

Для этого раздела вам понадобится сертификат сервера (смотрите этот раздел, чтобы узнать, как получить сертификат сервера).

Как работает код?

Этот пример похож на предыдущие, но добавляет необходимые строки для проверки сертификата сервера.

Сначала подключаем необходимые библиотеки. Вы будете использовать библиотеку WiFiClientSecure для выполнения запросов с использованием TLS и библиотеку ESP8266HTTPClient для удобного выполнения запросов.

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>

Корневой сертификат сервера для веб-сайта howsmyssl.com сохранён в переменной IRG_Root_X1.

// Root certificate for howsmyssl.com
const char IRG_Root_X1 [] PROGMEM = R"CERT(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)CERT";

Вставьте ваши сетевые учётные данные в следующие строки:

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Затем вам нужно создать список сертификатов cert (даже если у вас только один сертификат) с сертификатом сервера, который вы хотите использовать:

// Create a list of certificates with the server certificate
X509List cert(IRG_Root_X1);

В setup() вам нужно настроить время на ESP8266, что необходимо для проверки сертификата.

// Set time via NTP, as required for x.509 validation
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");

Serial.print("Waiting for NTP time sync: ");
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) {
  delay(500);
  Serial.print(".");
  now = time(nullptr);
}
Serial.println("");
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
Serial.print("Current time: ");
Serial.print(asctime(&timeinfo));

Во-первых, для выполнения HTTPS-запроса вам нужно создать объект WiFiClientSecure.

WiFiClientSecure client;

Затем вам нужно указать, каким сертификатам клиент может доверять, используя метод setTrustAnchors() и передав в качестве аргумента список сертификатов cert (в данном случае мы добавили только один сертификат).

client.setTrustAnchors(&cert);

Далее код такой же, как в предыдущих проектах.

Вам нужно создать экземпляр HTTPClient (https), инициализировать https-клиент на указанном хосте с помощью метода begin(), а затем обработать ответ сервера.

client.setTrustAnchors(&cert);

HTTPClient https;

Serial.print("[HTTPS] begin...\n");
if (https.begin(client, "https://www.howsmyssl.com/a/check")) {  // HTTPS

  Serial.print("[HTTPS] GET...\n");
  // start connection and send HTTP header
  int httpCode = https.GET();


 // httpCode will be negative on error
  if (httpCode > 0) {
    // HTTP header has been send and Server response header has been handled
    Serial.printf("[HTTPS] GET... code: %d\n", httpCode);

     // file found at server
    if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
      String payload = https.getString();
      Serial.println(payload);
    }
  } else {
    Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
  }

После загрузки этого кода на плату ESP8266 вы должны получить те же сообщения в мониторе порта, что и в предыдущих примерах.

ESP8266 HTTPS-запросы монитор порта

ESP8266 HTTPS-запросы – хранилище корневых сертификатов

Вместо сохранения только одного сертификата на ESP8266 вы можете сохранить несколько сертификатов. Вы можете добавить два, три или больше сертификатов, и вы даже можете добавить хранилище корневых сертификатов. Как мы видели ранее, хранилище корневых сертификатов — это база данных корневых сертификатов, которым ваш браузер или операционная система могут доверять.

Вы можете скачать всё хранилище сертификатов Mozilla и загрузить его на свой ESP8266, чтобы он вёл себя как браузер. Таким образом, вы сможете безопасно выполнять HTTPS-запросы к любому серверу (который использует TLS) без необходимости жёстко прописывать его сертификат.

Эта статья уже достаточно длинная, поэтому мы рассмотрим эту тему в другом руководстве (будет опубликовано в ближайшее время).

Если вам интересна эта тема, рекомендуем ознакомиться с официальным примером ESP8266 Certificate Store: BearSSL_CertStore. Вы также можете найти его в вашей Arduino IDE: File > Examples > ESP8266WiFi > BearSSL_CertStore.

Заключение

В этом руководстве вы узнали, как выполнять HTTPS-запросы с помощью ESP8266.

Мы показали вам различные способы выполнения HTTPS-запросов с ESP8266: без сертификата, с отпечатком и с сертификатом. Также возможно использовать несколько сертификатов или хранилище корневых сертификатов — мы рассмотрим эту тему в будущем руководстве. Вы также узнали об основных концепциях протокола HTTPS и о сертификатах SSL/TLS.

Другие связанные руководства, которые могут вас заинтересовать:

Мы надеемся, что это руководство было для вас полезным. Мы планируем создать больше руководств по HTTPS и безопасной связи. Напишите в комментариях ниже, что вы думаете.

Узнайте больше о ESP8266 с помощью наших ресурсов: