Nesnelerin İnterneti (IoT) ekosisteminde çalışan geliştiricilerin karşılaştığı en büyük yanılgılardan biri, sahada çalışan cihazların güvenliğini ikinci plana atmaktır. Fabrikada bir sıcaklık sensöründen, akıllı tarım sulama vanasına kadar ağa bağlı her mikrodenetleyici açık bir saldırı hedefi olabilir.
Bu yazımızda; popüler çift çekirdekli ESP32 çipi üzerinde MQTT protokolünü düz metin (plain-text) yerine TLS/SSL (MQTTS - Port 8883) ile nasıl zırhlandıracağınızı, sertifika yönetimini ve kesintisiz çalışan üretim standardında bir C++ kod şablonunu adım adım ele alıyoruz.
1. Neden MQTT ve Neden Şifreleme?
HTTP protokolü gibi her istekte ağır başlık (header) paketleri göndermek yerine MQTT, son derece hafif bir Yayınla/Abone Ol (Publish/Subscribe) mimarisi kullanır. 2 baytlık başlık boyutuyla GSM şebekelerinde veya zayıf Wi-Fi bağlantılarında dahi sorunsuz çalışır.
Ancak varsayılan MQTT (Port 1883), verileri şifrelemeden iletir. Aynı yerel ağdaki (LAN) herhangi bir cihaz, Wireshark gibi araçlarla sensör verilerinizi, kullanıcı adınızı ve broker şifrenizi açık metin olarak görebilir. Bu sebeple endüstriyel standart, iletimin MQTTS (TLS 1.2/1.3 üzerinden Port 8883) ile yapılmasıdır.
2. Sertifika Yönetimi (CA Certificate)
Broker sunucusunun gerçekten bağlandığımız güvenilir sunucu olduğunu doğrulamak için ESP32'nin flaş belleğinde sunucunun kök sertifikası (Root Certificate Authority - CA) tutulmalıdır. HiveMQ, Mosquitto, AWS IoT veya EMQX gibi broker servislerinin Root CA sertifikaları (örneğin Let's Encrypt ISRG Root X1) koda `PROGMEM` olarak gömülür.
3. Çalışan ESP32 Arduino C++ Kodu
Aşağıdaki kod; Wi-Fi bağlantısı kopsa veya MQTT sunucusu yeniden başlasa dahi kendi kendine kurtulabilen (self-healing), TLS korumalı bir ESP32 sensör gönderim örneğidir:
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
// Ağ ve Broker Bilgileri
const char* ssid = "WIFI_ADINIZ";
const char* password = "WIFI_SIFRENIZ";
const char* mqtt_server = "broker.kodkatman.com";
const int mqtt_port = 8883;
const char* mqtt_user = "cihaz_01";
const char* mqtt_pass = "GucluSifre123!";
// Sunucu Root CA Sertifikası (PEM Formatı)
const char* root_ca PROGMEM = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHg0dVbqQbSybEi6\n" \
"...\n" \
"-----END CERTIFICATE-----\n";
WiFiClientSecure espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
void setup_wifi() {
Serial.println("Wi-Fi baglantisi baslatiliyor...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi Baglandi! IP: " + WiFi.localIP().toString());
}
void reconnect() {
while (!client.connected()) {
Serial.print("MQTTS baglantisi kuruluyor...");
String clientId = "ESP32Client-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("Baglanti Basarili!");
client.subscribe("fabrika/komutlar/#");
} else {
Serial.print("Hata kodu: ");
Serial.print(client.state());
Serial.println(" 5 saniye sonra tekrar denenecek.");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
// SSL Kök Sertifikasını Tanımla
espClient.setCACert(root_ca);
client.setServer(mqtt_server, mqtt_port);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Her 10 saniyede bir telemetri verisi gonder
unsigned long now = millis();
if (now - lastMsg > 10000) {
lastMsg = now;
// Örnek Sensör Verisi (Sıcaklık ve Nem)
float temp = 24.5 + (random(-10, 10) / 10.0);
float humidity = 55.0 + (random(-20, 20) / 10.0);
String payload = "{\"device\":\"esp32_01\",\"temp\":" + String(temp, 2) +
",\"hum\":" + String(humidity, 2) + "}";
client.publish("fabrika/sensor/telemetri", payload.c_str());
Serial.println("Gonderilen Veri: " + payload);
}
}
4. Sahada Sık Karşılaşılan Sorunlar ve Çözümleri
- NTP Saat Senkronizasyonu (Saat Hatası): Sertifikaların geçerlilik tarihi (Valid From / Valid To) vardır. Eğer ESP32'nin sistem saati 1970 varsayılanında kalırsa sertifika "henüz geçerli değil" hatası verir. Kodun başına `configTime(0, 0, "pool.ntp.org");` ekleyerek doğru saati çekmek hayati önem taşır.
- Keep-Alive Zaman Aşımı: Sensör okuması yaparken uzun `delay()` blokları kullanırsanız MQTT arka plan ping paketleri iletilemez ve broker bağlantıyı düşürür. `delay()` yerine her zaman `millis()` tabanlı zamanlayıcılar kullanılmalıdır.
5. Sonuç
Endüstri 4.0 ve IoT dünyasında veri güvenliği sonradan eklenen bir yama değil, baştan kurgulanan bir temel olmalıdır. ESP32 gibi düşük maliyetli ancak güçlü bir çip ile MQTTS protokolü kullanarak sensör ağlarınızı kurumsal seviyede güvenli hale getirebilirsiniz.