MQTT Güvenliği

MQTT İçin ESP32 Sertifika Sabitleme ve CA Doğrulama

Bir ESP32'de broker sertifikasını doğrulamanın üç yolu: bir kök CA gömmek, ESP-IDF sertifika paketini kullanmak veya sabitlemek. Artılarını ve eksilerini öğrenin ve her biri için çalışan MQTT kodu alın.

TLS üzerinden bir MQTT broker'a bağlanırken sabitlenmiş bir kök sertifika tutan mikrodenetleyiciyi gösteren ESP32 sertifika sabitleme illüstrasyonu
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

ESP32 sertifika sabitleme (certificate pinning), bir kök CA gömmek ve ESP-IDF sertifika paketini kullanmak, cihazınızın bir sahtekârla değil gerçek MQTT broker ile konuştuğundan emin olmanın üç farklı yoludur. Bu eğitim üçünü dürüstçe karşılaştırır, hangisinin sertifika yenilemelerinden sağ çıktığını açıklar ve 8883 portunda bir MQTT broker'a bağlanan, çalışan Arduino ve ESP-IDF kodu verir.

Mikrodenetleyicilerde Doğrulama Neden Önemlidir?

Pek çok ESP32 eğitimi "TLS'i çalıştırmak" için client.setInsecure() çağırır. Bu trafiği şifreler ama sunucu kimlik doğrulamasını tamamen atlar. Ağdaki bir saldırgan, örneğin aynı SSID'ye sahip sahte bir erişim noktası, herhangi bir sertifika sunabilir, cihazın MQTT kullanıcı adını ve parolasını alabilir ve her mesajı aktarabilir veya değiştirebilir. Kimlik doğrulama olmadan şifreleme sizi yalnızca pasif dinleyicilere karşı korur.

Bir dizüstü bilgisayarın aksine ESP32'nin işletim sistemi CA deposu yoktur. Cihazın neye güveneceğine siz karar verip bunu firmware'e koymalısınız. Bu karar aynı zamanda broker sertifikaları değiştiğinde cihazın yıllar sonra nasıl davranacağını da belirler; bu yüzden bulduğunuz ilk kod parçasını kopyalamaktan daha fazla düşünmeyi hak eder.

Üç Doğrulama Stratejisinin Karşılaştırması

Strateji Cihazın güvendiği Leaf yenilemesinden etkilenmez CA değişikliğinden etkilenmez Flash maliyeti Emek
Gömülü kök CA Bir veya iki kök sertifika Evet Yalnızca kök aynı kalırsa Küçük (PEM başına yaklaşık 2 KB) Düşük
ESP-IDF sertifika paketi Çok sayıda yaygın herkese açık kök Evet Genellikle evet Daha büyük (onlarca KB) Düşük
Leaf sertifika veya anahtar sabitleme Tam olarak bir sunucu sertifikası veya anahtarı Çoğu zaman hayır Hayır Çok küçük Yüksek (OTA disiplini gerekir)

Gömülü Kök CA (Önerilen Varsayılan)

Broker'ın zincirini sabitleyen kök sertifikayı gömersiniz. O kök altında doğru hostname için verilmiş her geçerli sertifika kabul edilir; böylece rutin yenilemeler cihaz için görünmez olur. Çoğu proje için doğru seçim budur. Kesin konuşmak gerekirse bu da bir sabitleme biçimidir: güveni bir tarayıcının güvendiği yüzlerce CA yerine tek bir CA'ya sabitlersiniz.

ESP-IDF Sertifika Paketi

ESP-IDF, firmware'e derlenebilen yaygın kök sertifikalardan oluşan bir paketle (Mozilla'nın listesinden türetilmiş) gelir. Cihaz, bir tarayıcının güvendiği herkese açık CA'ların aynısına güvenir. Biraz katılıktan vazgeçersiniz, ancak broker bir gün farklı bir herkese açık CA'ya geçerse cihazlar çalışmaya devam eder.

Leaf veya Açık Anahtar Sabitleme

Sunucunun tam sertifikasının veya açık anahtarının parmak izini koda gömersiniz. En dar güveni sunar, ancak sunucu sertifikası her değiştirildiğinde bozulur. Kısa ömürlü olan ve otomatik yenilenen Let's Encrypt sertifikalarında leaf sertifika birkaç ayda bir veya daha sık değiştirilir ve anahtar da değişebilir. Böyle bir broker'ın leaf sertifikasını sabitlemek, bir filoyu çevrimdışı bırakmanın güvenilir bir yoludur. Leaf anahtarlarını yalnızca sunucuyu kontrol ettiğinizde, anahtarı bilinçli olarak sabit tuttuğunuzda ve herhangi bir değişiklikten önce OTA güncellemesi gönderebildiğinizde sabitleyin.

Arduino ile ESP32'de Kök CA'ya Sertifika Sabitleme

ConnectMQ broker'ı bir Let's Encrypt sertifikası sunar. Let's Encrypt'in mevcut zincirleri ISRG Root X1'e (RSA) çıkar; ayrıca ISRG Root X2'yi (ECDSA) de işletir. İkisini birden gömmek, gelecekteki bir zincir değişikliği için pay bırakan dar bir güven kümesi sağlar. PEM dosyalarını Let's Encrypt sertifikalar sayfasından indirin ve tam içeriklerini art arda aşağıdaki dizeye yapıştırın. mbedTLS, tek bir tampondaki birden çok birleştirilmiş PEM sertifikasını ayrıştırır.

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

const char* WIFI_SSID = "your-ssid";
const char* WIFI_PASS = "your-password";

const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 8883;
const char* CLIENT_ID = "esp32-pin-5b21";   // özel bir broker'da YOUR_CLIENT_ID kullanın
const char* TOPIC = "connectmq/demo/5b21/status";

// Sabitlenmiş güven çapaları: ISRG Root X1 ve ISRG Root X2'nin tam PEM'lerini yapıştırın
static const char PINNED_ROOTS[] = R"PEM(
-----BEGIN CERTIFICATE-----
...ISRG Root X1...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...ISRG Root X2...
-----END CERTIFICATE-----
)PEM";

WiFiClientSecure tlsClient;
PubSubClient mqtt(tlsClient);

void syncClock() {
  configTime(0, 0, "pool.ntp.org", "time.google.com");
  Serial.print("Waiting for NTP");
  while (time(nullptr) < 1700000000) {
    delay(300);
    Serial.print(".");
  }
  Serial.println(" done");
}

void connectMqtt() {
  while (!mqtt.connected()) {
    Serial.print("Connecting to MQTT over TLS... ");
    // Özel broker: mqtt.connect(CLIENT_ID, "YOUR_USERNAME", "YOUR_PASSWORD")
    if (mqtt.connect(CLIENT_ID)) {
      Serial.println("connected");
      mqtt.publish(TOPIC, "online", true);
    } else {
      char err[100];
      tlsClient.lastError(err, sizeof(err));
      Serial.printf("failed, state=%d, tls=%s\n", mqtt.state(), err);
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  Serial.println("Wi-Fi connected");

  syncClock();
  tlsClient.setCACert(PINNED_ROOTS);
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setBufferSize(512);
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  static unsigned long last = 0;
  if (millis() - last > 10000) {
    last = millis();
    char msg[48];
    snprintf(msg, sizeof(msg), "{\"uptime\":%lu}", millis() / 1000);
    mqtt.publish(TOPIC, msg);
  }
}

lastError() çağrısını üretim derlemelerinde tutmaya değer: belirsiz bir state=-2 değerini süresi dolmuş sertifika veya bilinmeyen CA gibi okunabilir bir mbedTLS mesajına dönüştürür. WiFiClientSecure hostname'i setServer() aracılığıyla aldığı için hostname doğrulaması otomatik olarak yapılır; bu yüzden hostname'i asla bir IP adresiyle değiştirmeyin.

ESP-IDF Sertifika Paketini Kullanmak

Doğrudan ESP-IDF ile derliyorsanız esp-mqtt bileşeni yerleşik pakete göre doğrulama yapabilir. Bunu menuconfig'te Component config, mbedTLS, Certificate Bundle altında etkinleştirin (varsayılan yaygın CA seçeneği yeterlidir), ardından:

#include "esp_crt_bundle.h"
#include "esp_log.h"
#include "mqtt_client.h"

static const char *TAG = "mqtt_bundle";

static void mqtt_event_handler(void *args, esp_event_base_t base,
                               int32_t event_id, void *event_data)
{
    esp_mqtt_event_handle_t event = event_data;
    if (event_id == MQTT_EVENT_CONNECTED) {
        ESP_LOGI(TAG, "Connected over TLS");
        esp_mqtt_client_publish(event->client,
                                "connectmq/demo/5b21/idf", "hello", 0, 1, 0);
    } else if (event_id == MQTT_EVENT_ERROR) {
        ESP_LOGE(TAG, "MQTT error, check TLS and credentials");
    }
}

void mqtt_start(void)
{
    const esp_mqtt_client_config_t cfg = {
        .broker.address.uri = "mqtts://broker.connectmq.com:8883",
        .broker.verification.crt_bundle_attach = esp_crt_bundle_attach,
        .credentials.client_id = "esp32-idf-5b21",
        // .credentials.username = "YOUR_USERNAME",
        // .credentials.authentication.password = "YOUR_PASSWORD",
    };
    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID,
                                   mqtt_event_handler, NULL);
    esp_mqtt_client_start(client);
}

mqtt_start() fonksiyonunu Wi-Fi bağlandıktan ve SNTP saati ayarladıktan sonra çağırın. ESP-IDF'te bunun yerine tek bir kök sabitlemek için .broker.verification.certificate alanını gömülü PEM dizenize ayarlayın ve crt_bundle_attach alanını ayarlamadan bırakın. Espressif ESP-MQTT dokümantasyonu tüm doğrulama seçeneklerini listeler.

Filonun Kilitlenmesini Önlemek

Hangi stratejiyi seçerseniz seçin, güven çapalarının değiştiği gün için tasarım yapın:

  1. Sunucu anahtarının yaşam döngüsüne sahip değilseniz leaf'leri değil kökleri sabitleyin.
  2. Bir yedek çapa gömün; örneğin aynı CA'dan ikinci bir kök, böylece bir zincir değişikliği bağlantıyı bozmaz.
  3. OTA güncellemelerini MQTT güveninden bağımsız tutun veya en azından MQTT TLS başarısız olduğunda OTA yolunun hâlâ çalıştığını test edin. MQTT üzerinden ESP32 OTA güncellemesi rehberimiz bir yaklaşım gösterir.
  4. Bağlanmadan önce saati senkronize edin. Core yapılandırmasına bağlı olarak mbedTLS sertifika geçerlilik tarihlerini kontrol eder ve 1970'te takılı kalmış bir saat her sertifikayı henüz geçerli değilmiş gibi gösterir.
  5. Bir bağlantı sonunda başarılı olduğunda TLS hatalarını uzaktan loglayın; böylece sahadaki doğrulama sorunlarını erkenden fark edersiniz.
  6. CA duyurularını takip edin. Herkese açık CA'lar kök ve ara sertifika değişikliklerini çok önceden duyurur; bakım takviminize bir hatırlatıcı ekleyin.

Sorun Giderme

  • "X509 - Certificate verification failed" ile state=-2: Yanlış veya eksik PEM ya da gömdüğünüz kök broker'ın zincirini sabitlemiyor. openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -showcerts ile kontrol edin.
  • "The certificate validity starts in the future": NTP tamamlanmamış.
  • Handshake sırasında bellek yetersizliği: TLS yaklaşık onlarca kilobayt heap'e ihtiyaç duyar; tamponları serbest bırakın, diğer ayırmaları azaltın ve aynı anda birden fazla TLS soketi açmaktan kaçının.
  • 1883'te çalışıyor, 8883'te başarısız oluyor: Bir güvenlik duvarı 8883'ü engelliyor olabilir. Kütüphaneniz destekliyorsa 8084 üzerinden güvenli WebSocket'i deneyin.

Daha fazla belirti için MQTT TLS handshake hatalarını düzeltme yazısına ve ESP32 ile SSL üzerinden MQTT eğitimimize bakın.

Projeniz İçin Strateji Seçmek

Bir hobi projesi veya elle yeniden flash'layabileceğiniz küçük bir filo için gömülü kök CA yaklaşımı açık ara kazanandır: birkaç satır kod, küçük flash maliyeti ve sertifika yenilemesinde sürpriz yok. Sahada yıllarca kalacak ticari bir ürün için önce CA değişikliği senaryosunu düşünün. Ya broker'ın CA'sından iki kök gömün ya da cihazların yaygın herhangi bir herkese açık CA'ya güvenmeye devam etmesi için ESP-IDF paketini kullanın ve MQTT TLS bir gün başarısız olursa OTA yolunuzun çalışmaya devam ettiğinden emin olun. Leaf sabitleme yalnızca sunucuyu sizin işlettiğiniz, anahtarını bilinçli olarak sabit tuttuğunuz ve anahtar değişmeden önce yeni bir pin'i dağıtmak için test edilmiş bir sürece sahip olduğunuz sistemlere aittir. Ne seçerseniz seçin, kararı firmware sürümünün yanına yazın; böylece filonun bakımını daha sonra üstlenen kişi hangi güven çapalarının nerede dağıtıldığını bilir.

Yönetilen Bir Broker Sabitlemeyi Neden Kolaylaştırır?

Sabitleme, sunucunun sertifika yönetimi kadar kararlıdır. Kendi barındırdığınız bir broker'da yenilemeler, zincir tercihleri ve anahtar değişiklikleri sizin sorumluluğunuzdadır ve her hata çevrimdışı cihazlar olarak ortaya çıkar. ConnectMQ gibi yönetilen bir MQTT broker, herkesçe güvenilen Let's Encrypt sertifikasını otomatik olarak yeniler; böylece Let's Encrypt köklerini sabitleyen cihazlar rutin yenilemeler boyunca bağlanmaya devam eder. Yukarıdaki kodla herkese açık MQTT test broker'ında prototip oluşturabilir, ardından TLS koduna dokunmadan özel kimlik bilgilerine geçebilirsiniz. Cihaz tarafındaki tam iş akışı için ESP32 IoT eğitimimizle başlayın.

ConnectMQ ile Başlayın

app.connectmq.com adresinden kaydolun, kredi kartı gerektirmeyen ücretsiz Serverless planı seçin ve bir broker oluşturun. Oluşturulan kullanıcı adını, parolayı ve client ID'yi yukarıdaki sketch'e kopyalayın, sabitlenmiş kökleri koruyun; ESP32'niz tam sertifika doğrulamasıyla 8883 portundan bağlanacaktır.

Sık Sorulan Sorular

setInsecure() test için kabul edilebilir mi?

Yalnızca tek kullanımlık kimlik bilgileriyle bir test tezgâhında. Sunucu kimlik doğrulamasını devre dışı bırakır; bu yüzden onu kullanan firmware'i asla yayımlamayın.

broker.connectmq.com'un sertifika parmak izini sabitlemeli miyim?

Hayır. Sunucu sertifikası otomatik olarak yenilenir ve parmak izi değişir. Bunun yerine Let's Encrypt kök sertifikalarını sabitleyin.

ESP-IDF sertifika paketi ne kadar flash kullanır?

Menuconfig'te hangi CA listesini seçtiğinize bağlıdır; tam yaygın CA listesi onlarca kilobayta mal olurken tek bir gömülü kök PEM yaklaşık iki kilobayt tutar.

Sertifika sabitleme kullanıcı adı ve parolanın yerini tutar mı?

Hayır. Sabitleme broker'ın kimliğini cihaza doğrular. Broker'ın da cihazın kimliğini doğrulayabilmesi için cihazın yine kendi kimlik bilgilerine ihtiyacı vardır.

İlgili yazılar

MQTT Kimlik Bilgileri Kesintisiz Nasıl Yenilenir?

Bir filo genelinde MQTT kullanıcı adı ve şifrelerini yenilemek için adım adım çift kimlik bilgisi stratejisi: yeni kimlik bilgisini hazırlayın, geri dönüş seçeneğiyle geçiş yapın, doğrulayın ve ancak ondan sonra eskisini iptal edin.

6 dk okuma

MQTT Kimlik Bilgilerini Gömülü Cihazlarda Güvenle Saklamak

ESP32 ve Linux cihazlarda MQTT kullanıcı adı ve şifrelerini korumanın yollarına pratik bir karşılaştırma; şifrelenmiş NVS ve flash şifrelemeden secure element'lere ve TPM destekli systemd kimlik bilgilerine kadar.

6 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.