# Laboratorium 2 - Architektura i model zagrożeń IoT.
# Autor rozwiązania: Igor Joński 112818, Jan Halusiak 84340
#
# ==========================================================================
# UKŁAD (Zadanie 1)
# ==========================================================================
#
# Płytka: Raspberry Pi Pico W (Wokwi: board-pi-pico-w), MicroPython v1.28.0.
#
# GP15 (GPIO15): linia danych DHT22
# GP16 (GPIO16): wyjście sterujące zewnętrzną LED alarmu
#
# Rezystor 10 kOhm - rezystor podciągający (pull-up) między 3V3 a linią
# danych DHT22. Utrzymuje na linii stan wysoki, gdy nic nie jest
# przesyłane, dzięki czemu odczyt jest stabilny.
#
# Rezystor 330 Ohm - połączony szeregowo z LED (GP16 -> 330 Ohm -> LED).
# Ogranicza prąd płynący przez diodę, chroni diodę i pin GP16.
#
# Zasilanie DHT22: 3V3 oraz wspólna masa GND.
#
# Działanie: LED świeci, gdy pomiar jest poprawny i temperatura >= 28 °C.
#
#
# ==========================================================================
# ARCHITEKTURA (Zadanie 2)
# ==========================================================================
#
# 1. Peryferia - czujnik DHT22 (temperatura, wilgotność) i dioda LED
# (sygnał alarmu).
# Status: URUCHOMIONE w Wokwi.
#
# 2. Węzeł IoT - Pico W. Odczytuje czujnik, sprawdza poprawność pomiaru,
# decyduje o włączeniu LED i przygotowuje rekord JSON.
# Status: URUCHOMIONE w Wokwi.
#
# 3. Brama - domowy router Wi-Fi (opcjonalnie koncentrator IoT).
# Status: CZĘŚCIOWO. Pico W łączy się tylko z wirtualną siecią
# Wokwi-GUEST. Prawdziwy router jest tylko częścią modelu.
#
# 4. Chmura i aplikacja - serwer (API), baza danych, aplikacja w telefonie.
# Status: TYLKO MODEL. Program niczego nie wysyła do serwera i nie
# odbiera poleceń. Rekord JSON jest jedynie wypisywany w konsoli.
#
#
# GRANICE ZAUFANIA
#
# Granica 1: czujnik DHT22 -> Pico W (przewód danych na GP15)
#
# Jakie dane: odczyt temperatury i wilgotności.
#
# Kto może wpłynąć: każdy, kto ma fizyczny dostęp do czujnika lub
# przewodu (może go ogrzać, schłodzić, odłączyć albo podmienić sygnał).
# Ten sam objaw może dać też zwykła awaria.
#
# Pico W ufa temu odczytowi. Walidacja odrzuci tylko wartości
# niemożliwe (np. 500 °C), ale nie wykryje fałszywej wartości, która
# wygląda normalnie (np. 22 °C zamiast 30 °C).
#
# Granica 2: Pico W -> Wi-Fi / router -> Internet -> chmura
#
# Jakie dane: rekord pomiaru (id, seq, temp, rh, ok, led, wifi).
# W pełnym systemie w drugą stronę płyną też polecenia i ustawienia
# z aplikacji.
#
# Kto może wpłynąć: osoby w zasięgu Wi-Fi, ktoś, kto przejmie router,
# dostawca Internetu, dostawca chmury, użytkownicy kont w aplikacji.
#
#
# ==========================================================================
# TESTY (Zadanie 3)
# ==========================================================================
#
# Test A - temperatura poniżej progu
# Ustawienia: 21 °C, 40 %, pełny układ, WIFI_WLACZONE = True
# Oczekiwany wynik: ok = true, led = 0
# Uzyskany wynik: ok = true, led = 0, dioda zgaszona
# Wniosek: poniżej progu 28 °C alarm się nie włącza.
#
# Test B - temperatura równa progowi
# Ustawienia: 28 °C, 40 %, pełny układ, WIFI_WLACZONE = True
# Oczekiwany wynik: ok = true, led = 1
# Uzyskany wynik: ok = true, led = 1, dioda świeci
# Wniosek: alarm włącza się już przy 28 °C, czyli próg działa włącznie.
#
# Dodatkowo sprawdzono: 24 °C -> led = 0, 29 °C -> led = 1,
# 27 °C -> led = 0.
#
# Test C - odłączony przewód danych czujnika
# Ustawienia: usunięte połączenie pico:GP15 - dht:SDA w diagram.json, 29 °C
# Oczekiwany wynik: ok = false, blad = "odczyt DHT22", led = 0
# Uzyskany wynik: rekordy z ok = false i blad = "odczyt DHT22",
# dioda nie zapaliła się mimo 29 °C, program działał dalej
# Wniosek: przy błędzie czujnika LED się wyłącza (stan bezpieczny),
# ale sam objaw nie mówi, czy to awaria, czy sabotaż.
# Po teście przewód przywrócono, odczyty wróciły do normy.
#
# Test D - wyłączone Wi-Fi
# Ustawienia: WIFI_WLACZONE = False, 29 °C, pełny układ
# Oczekiwany wynik: wifi = false, led = 1
# Uzyskany wynik: wifi = false, led = 1, dioda świeci
# Wniosek: alarm działa lokalnie i nie zależy od połączenia z siecią.
# Po teście przywrócono WIFI_WLACZONE = True.
#
#
# ==========================================================================
# ZAGROŻENIA (Zadanie 4)
# ==========================================================================
#
# Zagrożenie 1 - fałszywy odczyt czujnika
#
# Kategoria STRIDE: T - modyfikacja (Tampering)
#
# Zasób: wiarygodny alarm temperatury
#
# Punkt wejścia: czujnik DHT22 i jego przewód danych (granica 1)
#
# Wymagany dostęp: fizyczny dostęp do czujnika
#
# Skutek: ktoś schładza czujnik albo podmienia sygnał na niższą, ale
# normalnie wyglądającą temperaturę. Alarm nie włącza się mimo
# przegrzania.
#
# Zabezpieczenie: drugi niezależny czujnik i porównywanie odczytów,
# wykrywanie nietypowych zmian (np. nagłego spadku temperatury),
# osłona i plomba na czujniku.
#
# Proponowany test: dodać w Wokwi drugi DHT22, ustawić suwakami różne
# wartości i sprawdzić, czy program zgłasza ostrzeżenie.
#
# Status: ZASYMULOWANO. Zmiana temperatury suwakiem (testy A i B)
# modeluje wpływ na czujnik. Samą podmianę sygnału tylko
# przeanalizowano.
#
# Ryzyko: ŚREDNIE. Skutek jest poważny (brak alarmu), ale atak wymaga
# fizycznego dostępu do czujnika wewnątrz domu.
#
# Zagrożenie 2 - brak łączności Wi-Fi
#
# Kategoria STRIDE: D - odmowa usługi (Denial of Service)
#
# Zasób: działanie alarmu i przesyłanie danych do chmury
#
# Punkt wejścia: połączenie Wi-Fi (granica 2)
#
# Wymagany dostęp: bycie w zasięgu Wi-Fi (zagłuszanie, rozłączanie
# urządzeń) albo zwykła awaria routera lub Internetu
#
# Skutek: dane i powiadomienia nie docierają do chmury i aplikacji.
# Lokalna dioda LED nadal działa.
#
# Zabezpieczenie: sterowanie lokalne niezależne od sieci (już jest
# w programie), zapamiętywanie rekordów i ponowne łączenie, alarm
# w chmurze, gdy urządzenie przestaje wysyłać dane, szyfrowanie WPA3.
#
# Proponowany test: test D oraz próba z nieistniejącą nazwą sieci
# (SSID) - program powinien wypisać komunikat o limicie łączenia
# i dalej odczytywać czujnik.
#
# Status: ZASYMULOWANO w teście D. Było to celowe wyłączenie Wi-Fi
# w kodzie, a nie atak na sieć.
#
# Ryzyko: ŚREDNIE. Zakłócenie Wi-Fi jest łatwe, lokalny alarm działa,
# ale osoba poza domem nie dostanie powiadomienia.
#
# Zagrożenie 3 - zmiana ustawień przez konto bez uprawnień
#
# Kategoria STRIDE: E - podniesienie uprawnień (Elevation of Privilege)
#
# Zasób: ustawienia urządzenia (próg alarmu)
#
# Punkt wejścia: serwer w chmurze (API) i aplikacja mobilna (granica 2)
#
# Wymagany dostęp: konto, które powinno mieć tylko podgląd (np. gość,
# domownik), albo przejęte konto
#
# Skutek: zmiana progu np. na 80 °C, przez co alarm nigdy się nie
# włącza.
#
# Zabezpieczenie: serwer sprawdza uprawnienia konta przy każdej zmianie,
# każde konto ma tylko niezbędne uprawnienia, logowanie dwuetapowe,
# zapisywanie historii zmian ustawień.
#
# Proponowany test: wysłać prośbę o zmianę progu z konta tylko do
# odczytu. Serwer powinien odmówić i zapisać próbę w logach.
#
# Status: TYLKO PRZEANALIZOWANO (hipoteza). Program nie ma serwera
# ani nie odbiera poleceń, więc nie jest to wynik badania.
#
# Ryzyko: WYSOKIE. Alarm można wyłączyć zdalnie, bez wchodzenia do
# domu, a błędy w kontroli uprawnień serwerów są częste.
#
#
# ==========================================================================
# OGRANICZENIA BADANIA
# ==========================================================================
#
# - Testy wykonano tylko w symulatorze Wokwi, a czas symulacji różni się
# od rzeczywistego.
# - Nie sprawdzono odporności prawdziwego czujnika na manipulację.
# - Nie sprawdzono zabezpieczeń routera.
# - Nie sprawdzono szyfrowania przesyłanych danych (program niczego
# nie wysyła).
# - Nie sprawdzono serwera w chmurze ani aplikacji mobilnej.
from machine import Pin
import dht
import time
import json
import network
from logika import poprawny_pomiar, stan_led
PIN_DHT = 15
PIN_LED = 16
PROG = 28.0
SSID = "Wokwi-GUEST"
WIFI_WLACZONE = True
ODSTEP_MS = 2000
def uruchom_wifi():
# Rozpoczyna łączenie z Wi-Fi bez pętli oczekiwania.
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, "")
return wlan
def main():
# Odczytuje czujnik, steruje LED i wypisuje telemetrię.
time.sleep_ms(100)
led = Pin(PIN_LED, Pin.OUT, value=0)
czujnik = dht.DHT22(Pin(PIN_DHT))
wlan = None
try:
if WIFI_WLACZONE:
wlan = uruchom_wifi()
except (OSError, RuntimeError):
print("Wi-Fi niedostępne; działa sterowanie lokalne.")
start = time.ticks_ms()
numer = 0
while True:
online = wlan is not None and wlan.isconnected()
if (wlan is not None and not online
and time.ticks_diff(time.ticks_ms(), start) > 10000):
wlan.active(False)
wlan = None
print("Limit łączenia; dalsza praca bez Wi-Fi.")
numer += 1
try:
czujnik.measure()
t = czujnik.temperature()
h = czujnik.humidity()
ok = poprawny_pomiar(t, h)
led.value(stan_led(t, h, PROG))
rekord = {"id": "wezel-01", "seq": numer,
"temp": t, "rh": h, "ok": ok,
"led": led.value(), "wifi": online}
except OSError:
led.off()
rekord = {"id": "wezel-01", "seq": numer,
"ok": False, "blad": "odczyt DHT22",
"led": 0, "wifi": online}
print(json.dumps(rekord))
time.sleep_ms(ODSTEP_MS)
if __name__ == "__main__":
main()
Loading
pi-pico-w
pi-pico-w