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:
- Sunucu anahtarının yaşam döngüsüne sahip değilseniz leaf'leri değil kökleri sabitleyin.
- 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.
- 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.
- 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.
- 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.
- 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 -showcertsile 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.



