MQTT TLS 1.3 handshake'i kısaltır, zayıf kriptografiyi kaldırır ve cipher suite seçimini sadeleştirir; ancak pille çalışan cihazlarda asıl maliyet başka yerlerden gelir. Bu yazıda MQTT bağlantıları açısından TLS 1.2 ile 1.3 arasında gerçekte neyin değiştiğini, hangi cipher suite'lere izin vermeniz gerektiğini, bağlantınızın neyi müzakere ettiğini nasıl ölçeceğinizi ve Python, Node.js ve Mosquitto istemcilerini nasıl mantıklı biçimde yapılandıracağınızı anlatıyoruz.
TLS Sürümü MQTT İçin Neden Önemli?
MQTT uzun ömürlü bir TCP bağlantısı üzerinde çalışır. Cihaz bir kez bağlanır, TLS handshake'ini yapar ve ardından saatlerce, hatta günlerce küçük mesajlar alışverişi yapar. Bu, sürekli açık cihazlar için handshake maliyetinin nadiren ödendiği, ancak birkaç dakikada bir uyanan pilli sensörler gibi uyuyup yeniden bağlanan cihazlar için çok sık ödendiği anlamına gelir. Bu cihazlarda enerji tüketimine handshake turları ve açık anahtar işlemlerine harcanan CPU süresi hâkimdir; dolayısıyla TLS sürümü ve cipher suite seçimi büyük önem taşır.
MQTT bağlantılarını güvenli hâle getirmekte yeniyseniz önce MQTT TLS yapılandırması rehberimizle başlayın, ince ayar detayları için buraya geri dönün.
Bir Bakışta TLS 1.2 ve TLS 1.3
| Özellik | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Tam handshake tur sayısı | Uygulama verisinden önce 2 | Uygulama verisinden önce 1 |
| Devam ettirilen handshake | 1 tur (session ID veya ticket) | 1 tur (PSK), isteğe bağlı 0-RTT |
| Anahtar değişimi | RSA veya (EC)DHE | Yalnızca (EC)DHE, her zaman forward secrecy |
| Cipher suite'ler | Çoğu zayıf veya eskimiş onlarca suite | Beş tanımlı, üçü yaygın kullanılan |
| Handshake'te sertifikanın şifrelenmesi | Hayır | Evet |
| CBC modu, RC4, SHA-1, statik RSA | İzinli (yapılandırmaya bağlı) | Kaldırıldı |
Yüksek gecikmeli bir hücresel bağlantıdaki istemci için her bağlantıda bir tur kazanmak fark edilir bir iyileşmedir. Yerel ağdaki bir cihaz içinse bu kazanç, kriptografik işlem yüküne kıyasla küçüktür.
Handshake Maliyeti Gerçekte Nereden Gelir?
Bir mikrodenetleyicide tam handshake'e üç işlem hâkimdir:
- Anahtar değişimi: genellikle X25519 veya P-256 eğrisi üzerinde bir ECDHE hesaplaması. Bu, her iki TLS sürümünde de gerçekleşir.
- Sertifika doğrulama: sunucu zincirindeki imzaların kontrol edilmesi. RSA imza doğrulaması ucuzdur; ECDSA doğrulaması istemcide daha maliyetlidir ama ECDSA sertifikaları daha küçüktür.
- Ağ turları: her biri radyoyu uyanık tutar.
TLS 1.3 tur sayısını azaltır ama açık anahtar işlemlerini ortadan kaldırmaz. Sık yeniden bağlanan cihazlar için en büyük kazanç genellikle oturum devamıdır (session resumption); bu yöntem sertifika doğrulamasını atlar ve TLS 1.3'ün anahtar değişimli PSK modunda forward secrecy'yi korumaya devam eder. Buna güvenmeden önce hem TLS yığınınızın hem de broker'ınızın bunu desteklediğini kontrol edin.
Donanım hızlandırma da önemlidir. ESP32 ailesi, RSA ve ECC'de kullanılan AES, SHA ve büyük sayı aritmetiğini mbedTLS üzerinden hızlandırır; bu da her iki TLS sürümünü bu çiplerde pratik kılar. Hızlandırma içermeyen daha küçük mikrodenetleyiciler, saf yazılımda hızlı çalışan ChaCha20-Poly1305'ten fayda görebilir.
MQTT TLS 1.3 Cipher Suite'leri
TLS 1.3, cipher suite'i (simetrik şifreleme ve hash) anahtar değişimi ve imza algoritmalarından ayırır. Pratikte karşılaşacağınız suite'ler şunlardır:
TLS_AES_128_GCM_SHA256: uygulanması zorunludur, AES donanımıyla hızlıdır, iyi bir varsayılandır.TLS_AES_256_GCM_SHA384: daha büyük anahtar, biraz daha yavaş, çoğunlukla politika gereği tercih edilir.TLS_CHACHA20_POLY1305_SHA256: AES hızlandırması olmayan CPU'larda mükemmeldir.
Üçü de kimlik doğrulamalı şifreleme (authenticated encryption) sağlar ve güçlü kabul edilir. Bunları kısıtlamanız nadiren gerekir. TLS 1.3 için tanımlanan diğer iki suite (CCM varyantları) çoğunlukla kısıtlı ortamlarda görülür.
TLS 1.2'yi hâlâ desteklemeniz gerekiyorsa yalnızca forward secrecy sağlayan AEAD suite'lerine izin verin:
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-CHACHA20-POLY1305
ECDHE-RSA-CHACHA20-POLY1305
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-GCM-SHA384
CBC, RC4, 3DES, NULL, EXPORT içeren suite'lerden ve statik RSA anahtar değişimi kullananlardan (ECDHE olmadan AES ile başlayan adlar) kaçının.
Bağlantınızın Neyi Müzakere Ettiğini Ölçmek
Bir broker'ın hangi sürümü desteklediğini asla varsaymayın; ölçün. OpenSSL her sürümü zorlayıp sonucu raporlayabilir:
# Negotiate the best version both sides support
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -brief </dev/null
# Force TLS 1.3
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -tls1_3 -brief </dev/null
# Force TLS 1.2
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -tls1_2 -brief </dev/null
Protocol version ve Ciphersuite satırları sonucu gösterir. Aynı testleri değerlendirdiğiniz her broker'a karşı çalıştırın ve broker ya da kütüphane güncellemelerinden sonra tekrarlayın; desteklenen sürümler zamanla değişebilir.
Handshake sürelerini bir betikten ölçmek için şu Python parçası bağlantı ve handshake gecikmesini ölçer:
import socket
import ssl
import time
HOST, PORT = "broker.connectmq.com", 8883
def handshake(version: ssl.TLSVersion) -> None:
ctx = ssl.create_default_context()
ctx.minimum_version = version
ctx.maximum_version = version
start = time.perf_counter()
try:
with socket.create_connection((HOST, PORT), timeout=10) as sock:
with ctx.wrap_socket(sock, server_hostname=HOST) as tls:
elapsed = (time.perf_counter() - start) * 1000
print(f"{tls.version()} {tls.cipher()[0]} {elapsed:.1f} ms")
except ssl.SSLError as exc:
print(f"{version.name} not negotiated: {exc.reason}")
for v in (ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3):
for _ in range(3):
handshake(v)
Birkaç kez çalıştırın; hızlı bir bağlantıda ağ dalgalanması (jitter) genellikle sürümler arasındaki farktan daha büyüktür.
İstemcileri Yapılandırmak
En güvenli istemci politikası "TLS 1.2 ve üstüne izin ver, en yenisini tercih et" yaklaşımıdır; böylece istemci ve sunucu ortak olan en iyi sürümü seçebilir.
Python (paho-mqtt 2.x)
import ssl
import paho.mqtt.client as mqtt
ctx = ssl.create_default_context() # zinciri ve hostname'i doğrular
ctx.minimum_version = ssl.TLSVersion.TLSv1_2 # daha eski sürümleri reddeder
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-tls13-c71e")
client.tls_set_context(ctx)
# client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.connect("broker.connectmq.com", 8883)
client.loop_start()
client.publish("connectmq/demo/c71e/tls", "negotiated securely", qos=1).wait_for_publish()
client.loop_stop()
client.disconnect()
Python'daki set_ciphers() yalnızca TLS 1.2 ve öncesini etkiler; TLS 1.3 suite'leri zaten sağlam olan OpenSSL varsayılanlarıyla yönetilir.
Node.js (MQTT.js v5)
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "node-tls13-c71e",
protocolVersion: 5,
minVersion: "TLSv1.2", // Node'un tls.connect fonksiyonuna aktarılır
});
client.on("connect", () => {
const sock = client.stream;
console.log("TLS:", sock.getProtocol(), sock.getCipher().name);
client.end();
});
Kendi Barındırdığınız Broker Olarak Mosquitto
Kendi Mosquitto broker'ınızı çalıştırıyorsanız sunucu tarafını siz kontrol edersiniz:
listener 8883
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
cafile /etc/mosquitto/certs/chain.pem
tls_version tlsv1.2
ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
ciphers_tls1.3 TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384
Mosquitto'da tls_version, listener'ın kabul ettiği minimum sürümü belirler. Sunucuyu yalnızca TLS 1.3 ile sınırlamak cazip gelebilir, ancak bu hâlâ yalnızca TLS 1.2 destekleyen eski firmware'leri ve gömülü TLS yığınlarını dışarıda bırakır.
Kısıtlı Cihazlar İçin Pratik Öneriler
- Bağlantıları açık tutun. Günde bir handshake, dakikada bir yapılan handshake'in herhangi bir optimizasyonundan daha ucuzdur.
- Oturum devamını kullanın: uyuması gereken cihazlarda, yığınınız destekliyorsa.
- Donanım kriptografisini etkinleştirin: SDK yapılandırmanızda.
- Yığınınızın TLS 1.3 durumunu kontrol edin. ESP-IDF'in kullandığı güncel mbedTLS sürümleri bir yapılandırma seçeneği olarak TLS 1.3 desteğiyle derlenebilir; eski SDK'lar yalnızca TLS 1.2 sunar, bu da yukarıda listelenen suite'lerle hâlâ güvenlidir.
- Firmware'de tek bir sürümü sabit kodlamayın. Sunucular değiştiğinde cihazların çalışmaya devam etmesi için müzakereye izin verin.
- Komutlar için 0-RTT'den kaçının. Early data yeniden oynatılabilir (replay); bu, aktüatör komutları için tehlikelidir.
ESP32 sertifika sabitleme rehberi gömülü TLS'nin sertifika tarafını ele alır; MQTT TLS handshake hatalarını düzeltme yazısı ise sürüm müzakeresi ters gittiğinde yardımcı olur.
Güvenlik Politikası Kontrol Listesi
Bir MQTT projesinin TLS politikasını yazarken bu listeyi kullanın:
- Minimum protokol sürümü: istemcilerde TLS 1.2; TLS 1.3'e izin verilir ve tercih edilir.
- TLS 1.2 suite'leri: yalnızca AES-GCM veya ChaCha20-Poly1305 ile ECDHE anahtar değişimi.
- TLS 1.3 suite'leri: politika AES-256 gerektirmedikçe kütüphane varsayılanları.
- Sertifika doğrulama ve hostname kontrolü: her zaman açık.
- Yeniden bağlanma stratejisi: mesaj başına bağlantı değil, backoff ile uzun ömürlü bağlantılar.
- Oturum devamı: uyuyan cihazlar için, yığının desteklediği yerlerde etkin.
- Gözden geçirme: her broker, kütüphane veya firmware güncellemesinden sonra OpenSSL sürüm testlerini yeniden çalıştırın.
Politikayı kısa ve yazılı tutmak denetimleri kolaylaştırır ve devre dışı bırakılmış bir sertifika kontrolü gibi tek seferlik "geçici" istisnaların üretime ulaşmasını engeller.
Sunucu İnce Ayarını Yönetilen Bir Broker'a Bırakın
Kendi barındırdığınız bir broker'da protokol kullanımdan kaldırmalarını, cipher önerilerini ve sertifika yenilemelerini kendiniz takip etmeniz gerekir. Yönetilen bir MQTT broker sunucu tarafını sizin yerinize üstlenir. ConnectMQ, Let's Encrypt sertifikasıyla 8883 portunda TLS ve 8084 portunda güvenli WebSocket sunar; böylece yalnızca yukarıdaki istemci politikasına ihtiyacınız kalır: sertifikayı doğrulayın, TLS 1.2 ve üstüne izin verin ve en iyi seçeneği müzakereye bırakın. Bu yazıdaki ölçümleri kendi ağınızdan çalıştırmak için herkese açık MQTT test broker'ını kullanın.
ConnectMQ ile Başlayın
app.connectmq.com adresinden ConnectMQ'ya kaydolun, kredi kartı gerektirmeyen ücretsiz Serverless planını seçin ve bir broker oluşturun. Yukarıdaki Python veya Node.js örneklerini oluşturulan kimlik bilgilerinizle bu broker'a yönlendirin ve bağlantınızın neyi müzakere ettiğini kontrol edin.
Sık Sorulan Sorular
TLS 1.2 MQTT için hâlâ güvenli mi?
Evet, AES-GCM veya ChaCha20-Poly1305 gibi AEAD şifreleriyle birlikte ECDHE anahtar değişimiyle sınırlandırıldığında güvenlidir. İstemcilerin mümkün olduğunda kullanabilmesi için yanında TLS 1.3'e de izin verin.
TLS 1.3 MQTT mesaj ek yükünü azaltır mı?
Kayda değer ölçüde hayır. Kayıt başına ek yük benzerdir; asıl kazanımlar daha kısa bir handshake, daha güçlü varsayılanlar ve şifrelenmiş sertifikalardır.
IoT cihazları hangi TLS 1.3 cipher suite'ini kullanmalı?
AES hızlandırmalı donanımda TLS_AES_128_GCM_SHA256, hızlandırması olmayan CPU'larda TLS_CHACHA20_POLY1305_SHA256. İkisi de güçlüdür.
MQTT ile 0-RTT early data kullanmalı mıyım?
Genellikle hayır. Early data bir saldırgan tarafından yeniden oynatılabilir ve bağlantılar uzun ömürlü olduğu için MQTT istemcileri bundan çok az kazanç elde eder.



