9. ünite / 10
IoT güvenliği ve Bluetooth Low Energy
TLS, cihaz başına kimlik, depoya girmeyen sırlar ve MQTT ACL ile cihazı koru; BLE'nin GATT modelini ve reklam aralığının pil ömrüne etkisini öğren.
Bu ünitenin sonunda
- Basit bir IoT tehdit modeli çıkarıp her tehdide bir önlem eşlemek
- ESP32'de CA sertifikasıyla TLS (8883) kurmak ve kimlik bilgisini NVS'te saklamak
- Mosquitto ACL'de %u ve %c ile her cihazı kendi konusuna kilitlemek
- BLE GATT hizmet/özellik yapısını ve reklam aralığı ile akım arasındaki ilişkiyi açıklamak
Ders notları
Bir IoT cihazı evin ya da seranın içinde duran, ağa bağlı küçük bir bilgisayardır. Kötü yapılandırılmış bir broker'a internetten herkes bağlanıp ısıtıcıyı açabilir. Güvenlik sonradan eklenen bir özellik değil, tasarım kararıdır.
Tehdit modeli
- Dinleme: şifresiz MQTT (1883) parolayı ve veriyi açık metin taşır. Önlem: TLS (8883).
- Araya girme: TLS var ama sertifika doğrulanmıyorsa (
setInsecure()) sahte broker konuşmayı okur. Önlem: CA sertifikasıyla doğrulama. - Kimlik çalma: tüm cihazlarda aynı parola varsa biri ele geçince hepsi düşer. Önlem: cihaz başına kimlik, üretimde NVS'e yazılır.
- Yetki aşımı: her istemci her konuya yazabiliyorsa bir sensör ısıtıcıyı açabilir. Önlem: ACL.
- Kötü güncelleme: imzasız OTA ile zararlı yazılım yüklenir. Önlem: imzalı görüntü ve güvenli önyükleme.
Sırlar ve ACL
Wi-Fi ve broker parolası secrets.h dosyasında tutulur ve .gitignore'a eklenir; daha iyisi kurulumda Preferences (NVS) ile cihaza yazmaktır. Mosquitto'da allow_anonymous false ve bir ACL dosyası: pattern write sera/%u/# satırı her kullanıcıyı yalnız kendi adıyla başlayan konuya yazdırır. Eşleşen bir deny her izni ezer, hiç kural eşleşmezse erişim reddedilir. Seri hata ayıklama portunu ve ayrıntılı günlükleri üretim yazılımında kapat.
BLE: yakın mesafe, düşük güç
Laboratuvardaki HC-05 klasik Bluetooth'tur: seri port gibi sürekli bağlantı, onlarca mA. BLE ise kısa olaylarla çalışır ve düğme pille aylarca dayanır. Veri GATT ile düzenlenir: hizmet (örneğin 0x181A Çevresel Algılama) içinde özellikler (0x2A6E sıcaklık, sint16, 0,01 °C). Özellik okunabilir, yazılabilir ya da notify ile değişince telefona itilebilir. 23,45 °C → 2345 → 0x0929 → küçük-endian 29 09.
Reklam aralığını 100 ms'den 1 s'ye çıkarmak ortalama akımı kabaca on kat düşürür ama telefonun cihazı bulması gecikir. ESP32'de Arduino için NimBLE, MicroPython için aioble kütüphanesi kullanılır.
Simülasyonlar
IoT güvenlik denetimi ve MQTT ACL
Bir cihaz kurulumunu denetle (TLS, sertifika doğrulama, anonim erişim, ortak parola, depodaki sırlar, imzalı OTA) ve risk puanını düşür. Altta Mosquitto tarzı ACL yaz ve hangi kullanıcının hangi konuya yazabildiğini sına.
- Trafik düz metin: parola ve veriler ağda okunur.
- Broker herkese açık: herkes abone olup komut yayımlayabilir.
- Tek cihaz ele geçerse hepsi ele geçer; tek cihazı iptal edemezsin.
- Sır git geçmişinde: silmek yetmez, parolayı değiştir.
- ACL yok: bir cihaz başka cihazın komut konusuna yazabilir.
- İmzasız OTA: ağdaki herkes cihaza yazılım yükleyebilir.
- Hata ayıklama kapısı açık: fiziksel ya da ağ erişimiyle sırlar okunur.
- Sertifika doğrulanmıyor: araya giren saldırgan broker gibi davranabilir.
| kullanıcı / istemci | konu | işlem | karar |
|---|---|---|---|
| sera-01 / sera-01 | sera/01/sicaklik | write | izin (satır 4) |
| sera-01 / sera-01 | sera/02/fan/set | write | ret |
| pano / pano-web | sera/02/fan/set | read | izin (satır 8) |
| pano / pano-web | sera/02/fan/set | write | izin (satır 9) |
| admin / cli | sera/03/kapi/ac | write | ret (satır 12) |
| sera-03 / sera-03 | clients/sera-03/durum | write | izin (satır 2) |
BLE: GATT hizmetleri ve reklam aralığı
Çevresel algılama, pil ve özel LED hizmetinin özelliklerini oku ve yaz; değerin küçük-endian baytlarını gör. Reklam aralığı ve verici gücüyle ortalama akımı, keşif süresini ve düğme pil ömrünü karşılaştır.
| Hizmet / özellik | UUID | Özellikler |
|---|---|---|
| Çevresel algılama | 0x181A | |
| ↳ Sıcaklık | 0x2A6E | read, notify |
| ↳ Bağıl nem | 0x2A6F | read, notify |
| Pil | 0x180F | |
| ↳ Pil düzeyi | 0x2A19 | read, notify |
| LED (özel hizmet) | 19b10000… | |
| ↳ LED durumu | 19b10001… | read, write |
Kod
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <Preferences.h>
#include "ca_cert.h" // broker CA sertifikası (genel, sır değil)
WiFiClientSecure tls;
PubSubClient mqtt(tls);
Preferences prefs;
void setup() {
prefs.begin("kimlik", true); // NVS: üretimde cihaza yazılır, kodda yok
String user = prefs.getString("user", "");
String pass = prefs.getString("pass", "");
prefs.end();
tls.setCACert(CA_CERT); // setInsecure() KULLANMA: araya giren saldırgana açık
mqtt.setServer("broker.example.com", 8883);
String id = "sera-" + String((uint32_t)ESP.getEfuseMac(), HEX);
// Kullanıcı adı = istemci kimliği: ACL %u/%c ile kendi konusuna kilitlenir
mqtt.connect(id.c_str(), user.c_str(), pass.c_str(), "sera/durum", 1, true, "offline");
}
void loop() { mqtt.loop(); }# mosquitto.conf
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
# acl (her cihaz yalnız kendi konusuna yazar)
pattern write sera/%u/#
pattern read sera/%u/+/set
user pano
topic read sera/#
topic write sera/+/+/setimport asyncio, struct
import aioble, bluetooth
ENV = bluetooth.UUID(0x181A) # Environmental Sensing hizmeti
TEMP = bluetooth.UUID(0x2A6E) # Sıcaklık: sint16, 0,01 °C
svc = aioble.Service(ENV)
ch = aioble.Characteristic(svc, TEMP, read=True, notify=True)
aioble.register_services(svc)
async def sensor():
t = 23.45
while True:
ch.write(struct.pack("<h", round(t * 100)), send_update=True) # 23,45 -> 0x0929 -> 29 09
await asyncio.sleep(5)
async def reklam():
while True:
# Reklam aralığı 250 ms: daha uzun = daha az akım, daha geç keşif
async with await aioble.advertise(250_000, name="sera-01", services=[ENV]) as conn:
await conn.disconnected()
asyncio.run(asyncio.gather(sensor(), reklam()))Kendin dene
Güvenlik simülasyonunda başlangıç kurulumunun risk puanını not et; TLS'i aç ama sertifika doğrulamayı kapalı bırak, sonra her bulguyu tek tek düzelterek puanı sıfıra indir. ACL düzenleyicisinde "sera-01" kullanıcısının "sera/02/fan/set" konusuna yazamadığını, pano kullanıcısının okuyabildiğini sına. BLE simülasyonunda sıcaklık özelliğinin baytlarını oku, reklam aralığını 100 ms'den 2 s'ye çıkar ve düğme pil ömrünü karşılaştır.
Sık yapılan hatalar
- TLS'i açıp setInsecure() kullanmak: şifreli ama kiminle konuştuğunu bilmeyen bir bağlantı araya girmeye açıktır.
- Wi-Fi parolasını kaynak koduna yazıp depoya göndermek: git geçmişinden silmek zordur.
- Bütün cihazlara aynı broker parolasını vermek: biri ele geçirilince hepsi tehlikeye girer.
- HC-05'i BLE sanmak: klasik Bluetooth'tur, telefon uygulamaları BLE GATT ile ona bağlanamaz.
- BLE sıcaklığını metin olarak göndermek: standart özellik sint16 küçük-endian bekler, hazır uygulamalar yanlış okur.
Yazılım mühendisliği bağlantısı
Güvenlik bir kontrol listesiyle başlar ama otomasyonla sürdürülür.
- Depoya sır girmesini engelleyen bir ön işleme kancası (ör. gitleaks) ve CI taraması ekle.
- ACL kurallarını kod gibi test et: "sensör kullanıcısı set konusuna yazamaz" gibi olumsuz testler olumlu testler kadar önemlidir;
aclChecksaf bir fonksiyon olduğu için bu kolaydır.
Kendini sına
ESP32 TLS ile bağlanıyor ama kod setInsecure() çağırıyor. Hangi saldırıya açıktır?
ACL'de "pattern write sera/%u/#" var. "sera-01" kullanıcısı hangi konuya yazabilir?
BLE sıcaklık özelliği (sint16, 0,01 °C) 21,50 °C için hangi baytları taşır?
Reklam aralığını 100 ms'den 1 s'ye çıkarmanın etkisi nedir?
Bu üniteden sonra bitirme projesinde
- Güç ve güvenlik: Derin uyku ile pil ömrü hesabı (en az 30 gün), TLS, cihaz başına kimlik ve ACL; güvenlik denetiminde risk puanı 20'nin altında.