Laboratorium 5
Zadania laboratoryjne dla studentów 7 semestru IT - ocena 4.0

Poziom: ocena 4.0 - programowanie protokołów, dekonstrukcja binarna i audyt bezpieczeństwa

Zestaw 10 praktycznych zadań laboratoryjnych do wykonania w trakcie zajęć (90–100 minut).
Kierunek: Informatyka, semestr 7, przedmiot: Kryptologia.
Podstawa materiałowa: wykład część 5 (bezpieczna wymiana informacji: PKI, TLS i uwierzytelnianie).

Wskazówki dla studenta i zasady realizacji:

  • Zadania na ocenę 4.0 wymagają implementacji skryptów w języku Python oraz analizy protokołów na poziomie binarnym: budowy walidatora łańcucha X.509, obsługi respondera OCSP i OCSP Stapling, symulacji klienta ACME dla wyzwań HTTP-01/DNS-01, binarnej dekonstrukcji rekordów pakietu TLS Handshake, symulacji architektury Kerberos KDC (AS i TGS), weryfikacji tokenów JWT i badania podatności 'alg: none', implementacji algorytmu TOTP od podstaw, podpisywania i weryfikacji S/MIME oraz DKIM, walidacji łańcucha DNSSEC oraz budowy skanera audytującego konfigurację TLS i nagłówki HSTS.
  • Wszystkie zadania są w pełni wykonalne bez praw administratora na systemie Windows - wymagają standardowego środowiska Python 3 z bibliotekami standardowymi oraz pakietem cryptography w konsoli JSLinux Alpine lub na lokalnej stacji roboczej.
  • Każde zadanie realizowane jest w czasie 90–100 minut w trakcie zajęć laboratoryjnych. Środowisko zamrożone: JSLinux Alpine + openssl 3.x, Python 3.11+, cryptography 41+. Najpierw próba online, przy awarii od razu fallback offline bez utraty punktów.
  • Wymagania formalne sprawozdania laboratoryjnego:
    • Strona tytułowa zawierająca: imię i nazwisko studenta, numer albumu, kierunek, semestr, grupę laboratoryjną, rok akademicki, numer i temat laboratorium, numer oraz nazwę realizowanego zadania, deklarowaną ocenę (4.0).
    • Opis konfiguracji środowiska badawczego, wersji bibliotek oraz wykorzystanych poleceń.
    • Szczegółowy opis wykonanych czynności, uzasadnienie wyboru narzędzi, kod źródłowy autorskich skryptów, zrzuty ekranu oraz wklejone fragmenty danych wejściowych i wyjściowych dokumentujące rzetelne wykonanie pracy.
    • Struktura skrócona na zajęcia: tytuł, cel, lista komend/kod, 2-3 zrzuty z podpisami, wnioski 3-5 zdań. Pełne spisy tabel/rysunków i bibliografia tylko w pracy domowej.
Kryptologia
lab 5 - 4.0
Spis
Spis zadań laboratoryjnych na ocenę 4.0
01/10
Zadanie 1. Parser i walidator łańcucha certyfikatów X.509 w języku Python (analiza ASN.1 DER, okresów ważności i podpisów)
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajdy 6, 7, 8, 9: struktura ASN.1 DER, TBSCertificate, Subject/Issuer, weryfikacja kryptograficzna podpisu wystawcy w Pythonie, rozszerzenia v3.
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest samodzielna implementacja skryptu w języku Python weryfikującego poprawność formalną i kryptograficzną łańcucha certyfikatów X.509. Student parsuje certyfikaty zakodowane w formatach PEM i DER, sprawdza okna ważności czasowej notBefore i notAfter, weryfikuje dopasowanie nazw wystawcy i podmiotu oraz kryptograficznie sprawdza podpis cyfrowy certyfikatu podrzędnego kluczem publicznym wystawcy.

Scenariusz – opis

Weryfikacja certyfikatów X.509 w aplikacjach sieciowych jest krytycznym zadaniem bibliotek kryptograficznych. Wielu programistów traktuje funkcje weryfikujące jako czarne skrzynki, nie rozumiejąc wewnętrznych kroków algorytmu RFC 5280. Każdy certyfikat X.509 składa się z części podpisywanej TBSCertificate, identyfikatora algorytmu podpisu oraz samego podpisu cyfrowego. W procesie walidacji klient musi najpierw sprawdzić okres ważności czasowej względem bieżącego czasu systemowego UTC. Następnie weryfikator sprawdza, czy pole Issuer badanego certyfikatu jest identyczne z polem Subject certyfikatu nadrzędnego. Kolejnym fundamentalnym krokiem jest kryptograficzna weryfikacja asymetrycznego podpisu cyfrowego.

Co ma wykonać student / grupa

W środowisku JSLinux lub w lokalnym interpreterze Pythona tworzysz plik skryptu cert_validator.py. Skrypt wczytuje plik certyfikatu serwera oraz certyfikat urzędu certyfikacji w formacie PEM. Za pomocą modułu x509 biblioteki cryptography dekodujesz oba obiekty do pamięci operacyjnej programu. Implementujesz funkcję sprawdzającą ważność czasową certyfikatu w oparciu o obiekt datetime w strefie UTC.

Wypisujesz na konsoli czytelną informację o datach not_valid_before oraz not_valid_after wraz ze statusem bieżącym. Tworzysz funkcję weryfikującą tożsamość wystawcy, porównującą pola certyfikat.issuer z wystawca.subject.

Przykładowe kroki do wykonania jako sugestia

  1. Uruchom konsolę i utwórz plik validator.py w dedykowanym katalogu roboczym.
  2. Zaimportuj niezbędne moduły: from cryptography import x509 oraz cryptography.hazmat.primitives.asymmetric.
  3. Zaimplementuj funkcję wczytującą plik PEM: cert = x509.load_pem_x509_certificate(f.read()).
  4. Napisz funkcję check_validity_dates( cert), sprawdzającą czy cert.not_valid_before_utc <= now <= cert.not_valid_after_utc.
  5. Wypisz sformatowane daty ważności certyfikatu oraz bieżący czas systemowy.
  6. Napisz funkcję check_issuer_match( cert, issuer_cert) porównującą cert.issuer.public_bytes() z issuer_cert.subject.public_bytes().
  7. Wyodrębnij klucz publiczny urzędu wystawcy: issuer_pubkey = issuer_cert.public_key().
  8. Zaimplementuj procedurę weryfikacji podpisu cyfrowego z obsługą dopełnienia PKCS#1 v1.5 lub RSA-PSS.
  9. Użyj metody: issuer_pubkey.verify(cert.signature, cert.tbs_certificate_bytes, padding.PKCS1v15(), cert.signature_hash_algorithm).
  10. Dołącz kod źródłowy skryptu oraz zrzuty ekranu z wykonania testu pozytywnego i negatywnego do sprawozdania.

Kontrola zaliczenia (checklist):

  1. Uruchomiono skrypt walidatora i zachowano log: parsowanie PEM/DER (TBSCertificate vs podpis), kontrola notBefore/notAfter, weryfikacja podpisów w łańcuchu do Root.
  2. Dołączono kod (szkielet + własne 20–40 linii): ładowanie cryptography, pętla łańcucha, obsługa błędów RFC 5280.
  3. Przeprowadzono test pozytywny (poprawny łańcuch) i negatywny (fałszywy wystawca o tej samej nazwie / wygasły — odrzut z powodem).
  4. Opisano w 3–5 zdaniach: ASN.1/TBS, okna czasowe, walidacja Basic Constraints i podpisów.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Głębokie zrozumienie algorytmu weryfikacji łańcucha zaufania X.509 zgodnie ze specyfikacją RFC 5280.
  • Umiejętność programowej manipulacji obiektami ASN.1, kluczami publicznymi i podpisami w bibliotece cryptography.
  • Zrozumienie technicznego podziału certyfikatu na blok danych TBSCertificate oraz sygnaturę cyfrową.
  • Praktyczna weryfikacja odporności kryptograficznej na próby podstawienia fałszywego wystawcy o tożsamej nazwie podmiotu.
Zadanie 1 - ilustracja
02/10
Zadanie 2. Budowa i programowa obsługa lokalnego respondera OCSP oraz symulacja mechanizmu OCSP Stapling w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajd 12: protokół OCSP (RFC 6960), zapytania na żywo, responder OCSP, odpowiedzi good/revoked/unknown, mechanizm OCSP Stapling (RFC 6066).
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest praktyczne zrozumienie działania protokołu OCSP (Online Certificate Status Protocol) oraz optymalizacji OCSP Stapling. Student tworzy w Pythonie prostą usługę respondera OCSP odpowiadającą na zapytania klientów, generuje kryptograficznie podpisane odpowiedzi ze statusem certyfikatu oraz symuluje proces dołączania zszytej odpowiedzi do procedury uzgadniania połączenia.

Scenariusz – opis

Pobieranie całych list unieważnień CRL wiąże się z opóźnieniami oraz dużym narzutem transmisyjnym. Standard RFC 6960 wprowadził protokół OCSP umożliwiający odpytywanie respondera o stan pojedynczego certyfikatu w czasie rzeczywistym. Klient TLS wysyła zapytanie zawierające skrót nazwy wystawcy, skrót klucza wystawcy oraz numer seryjny badanego certyfikatu. Responder działający w imieniu CA weryfikuje bazę statusów i odsyła podpisaną odpowiedź: good, revoked lub unknown. Choć OCSP zapewnia świeżość danych, niesie ze sobą istotne wady: opóźnia nawiązywanie sesji oraz ujawnia responderowi strony odwiedzane przez użytkownika. Rozwiązaniem tych problemów jest technika OCSP Stapling opisana w RFC 6066, zwana formalnie Certificate Status Request.

Co ma wykonać student / grupa

W konsoli JSLinux lub w środowisku Pythona przygotowujesz plik skryptu ocsp_responder.py. Skrypt wykorzystuje moduł ocsp z biblioteki cryptography do budowy zapytań i odpowiedzi. Tworzysz funkcję generującą zapytanie OCSP OCSPRequestBuilder dla wybranego numeru seryjnego certyfikatu. Serializujesz zapytanie do postaci binarnej DER i analizujesz jego niewielki rozmiar w porównaniu z plikami CRL.

W module serwera respondera implementujesz logikę przeszukiwania lokalnej bazy certyfikatów pod kątem odpytywanego numeru seryjnego. Budujesz obiekt odpowiedzi OCSPResponseBuilder, ustawiając status certyfikatu OCSPCertStatus.GOOD lub REVOKED.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik skryptu ocsp_demo.py w katalogu projektowym.
  2. Zaimportuj moduły: from cryptography.x509 import ocsp, hashes, load_pem_x509_certificate.
  3. Wczytaj certyfikat serwera oraz certyfikat wystawcy z dysku.
  4. Zbuduj zapytanie OCSP: builder = ocsp.OCSPRequestBuilder().add_certificate( cert, issuer_cert, hashes.SHA256()).
  5. Wygeneruj obiekt żądania: req = builder.build() i zapisz go w formacie DER: req_der = req.public_bytes(serialization.Encoding.DER).
  6. Wypisz rozmiar żądania DER w bajtach (zauważ, że wynosi on zazwyczaj poniżej 100 bajtów).
  7. Zaimplementuj generator odpowiedzi respondera: resp_builder = ocsp.OCSPResponseBuilder().
  8. Ustaw status GOOD dla badanego certyfikatu oraz określ czasy this_update i next_update (np. ważne przez 24 godziny).
  9. Podpisz odpowiedź kluczem CA: ocsp_resp = resp_builder.sign(ca_key, hashes.SHA256()).
  10. Zapisz zrzuty ekranu prezentujące działanie skryptu oraz sporządź diagram sekwencji protokołu OCSP Stapling.

Kontrola zaliczenia (checklist):

  1. Uruchomiono responder OCSP i zachowano log: zapytanie→odpowiedź (good/revoked), podpis respondera, demo staplingu (status w handshake zamiast zapytania klienta).
  2. Dołączono kod (własne 20–40 linii): budowa OCSPRequest/Response, klucze respondera, thisUpdate/nextUpdate.
  3. Przeprowadzono test pozytywny (good przechodzi) i negatywny (revoked / przeterminowany nextUpdate — odrzut, wykryty replay starego).
  4. Opisano w 3–5 zdaniach: świeżość vs CRL, prywatność/wydajność staplingu, okna czasowe.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Zrozumienie zalet protokołu OCSP w stosunku do statycznych list CRL pod kątem świeżości i rozmiaru danych.
  • Praktyczna znajomość problemów prywatności i wydajności tradycyjnego OCSP rozwiązanych przez mechanizm OCSP Stapling.
  • Umiejętność programowej generacji i kryptograficznej walidacji odpowiedzi OCSP w języku Python.
  • Zrozumienie roli pól czasowych thisUpdate i nextUpdate w zapobieganiu atakom powtórzenia starych poświadczeń statusu.
Zadanie 2 - ilustracja
03/10
Zadanie 3. Implementacja klienta protokołu ACME i automatyzacja wyzwań HTTP-01 / DNS-01 w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajd 10: proces wydawania certyfikatów, automatyzacja ACME (RFC 8555), Let's Encrypt, typy wyzwań HTTP-01 i DNS-01, autoryzacja klucza.
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest dekonstrukcja i implementacja kluczowych elementów kryptograficznych protokołu ACME (Automated Certificate Management Environment). Student programuje w języku Python mechanizm autoryzacji konta, generuje thumbprint klucza publicznego, wylicza wartość autoryzacji wyzwania keyAuthorization oraz implementuje symulację obsługi wyzwania HTTP-01 oraz DNS-01.

Scenariusz – opis

Pojawienie się inicjatywy Let's Encrypt zrewolucjonizowało wdrażanie kryptografii w internecie dzięki pełnej automatyzacji. Sercem tego ekosystemu jest protokół ACME ustandaryzowany w dokumencie RFC 8555 przez organizację IETF. W protokole ACME administrator serwera nie wypełnia formularzy ani nie wysyła ręcznych wiadomości e-mail. Zamiast tego klient ACME komunikuje się z serwerem urzędu za pomocą podpisanych kryptograficznie komunikatów JSON Web Signature. Aby potwierdzić prawo do dysponowania domeną, serwer CA stawia przed klientem kryptograficzne wyzwanie challenge. Najpopularniejszym wyzwaniem jest HTTP-01 polegające na udostępnieniu wskazanego pliku pod ustandaryzowaną ścieżką /.well-known/acme-challenge/.

Co ma wykonać student / grupa

W katalogu roboczym tworzysz plik acme_client.py, w którym zaimplementujesz matematykę protokołu RFC 8555. Generujesz asymetryczną parę kluczy konta ACME z wykorzystaniem krzywej eliptycznej P-256 lub algorytmu RSA. Implementujesz funkcję wyliczającą z klucza publicznego znormalizowany obiekt JSON Web Key JWK według reguł RFC 7638. Zgodnie ze standardem klucze w słowniku JWK muszą być posortowane leksykograficznie, a zbędne białe znaki usunięte.

Obliczasz skrót SHA-256 ze znormalizowanego ciągu JSON i kodujesz go w formacie Base64URL, uzyskując JWK Thumbprint. Definiujesz funkcję generującą odpowiedź wyzwania keyAuthorization łączącą token wyzwania z odciskiem klucza konta znakiem kropki.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik acme_client.py i zaimportuj moduły: hashlib, json, base64, socket z biblioteki standardowej Pythona.
  2. Użyj biblioteki cryptography do wygenerowania klucza konta: acct_key = ec.generate_private_key(ec.SECP256R1()).
  3. Wyodrębnij współrzędne x i y klucza publicznego krzywej eliptycznej.
  4. Zbuduj słownik JWK zawierający pola: {'crv': 'P-256', 'kty': 'EC', 'x': x_b64, 'y': y_b64}.
  5. Zapewnij kanoniczną postać JSON: kanon_json = json.dumps(jwk, sort_keys=True, separators=(',', ':')).
  6. Oblicz thumbprint konta: thumbprint = base64_url_encode(hashlib.sha256(kanon_json.encode()).digest()).
  7. Zdefiniuj przykładowy token wyzwania otrzymany z CA: token = 'DqlZmKXjpGnDYr7ngB0r_w'.
  8. Wyznacz ciąg autoryzacyjny: key_auth = f'{token}.{thumbprint}'.
  9. Napisz funkcję dla wyzwania DNS-01: dns_record_value = base64_url_encode(hashlib.sha256(key_auth.encode()).digest()).
  10. Zapisz zrzuty ekranu z konsoli oraz pełny kod skryptu do sprawozdania laboratoryjnego.

Kontrola zaliczenia (checklist):

  1. Uruchomiono klienta ACME i zachowano log: konto, thumbprint JWK (RFC 7638, Base64URL), token HTTP-01/DNS-01 oraz finalizacja (mock CA).
  2. Dołączono kod (własne 20–40 linii): wyliczanie thumbprintu, budowa key-auth, endpoint weryfikacyjny.
  3. Przeprowadzono test pozytywny (poprawne wyzwanie przechodzi) i negatywny (zły token/klucz — błąd autoryzacji).
  4. Opisano w 3–5 zdaniach: RFC 8555, HTTP-01 vs DNS-01, Base64URL/JWK.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Głębokie zrozumienie kryptograficznych podstaw automatyzacji certyfikacji w protokole ACME (RFC 8555).
  • Praktyczna znajomość metody wyliczania JWK Thumbprint (RFC 7638) oraz formatowania danych Base64URL.
  • Zrozumienie technicznych różnic pomiędzy wyzwaniem webowym HTTP-01 a wyzwaniem domenowym DNS-01.
  • Umiejętność samodzielnej implementacji endpointu weryfikacyjnego dla automatycznych robotów certyfikacyjnych.
Zadanie 3 - ilustracja
04/10
Zadanie 4. Ręczna dekonstrukcja i analiza rekordów pakietu TLS Handshake (ClientHello, ServerHello) w Pythonie i Scapy
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajdy 14, 15, 16, 20: architektura warstwy rekordów TLS, podprotokoły Handshake i Alert, struktura pakietu ClientHello, rozszerzenia TLS (SNI, Supported Groups, ALPN).
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest dogłębna analiza struktury binarnej rekordów protokołu TLS na poziomie warstwy transportowej. Student pisze skrypt w Pythonie analizujący surowe pakiety TLS Handshake (ClientHello i ServerHello), dekomponuje nagłówki warstwy rekordów, identyfikuje wartości losowe Random, odczytuje listę proponowanych ciphersuites oraz parsuje rozszerzenia binarne.

Scenariusz – opis

Większość administratorów i deweloperów postrzega protokół TLS jedynie przez pryzmat interfejsu gniazd sieciowych. Jednak w celu rzetelnej analizy bezpieczeństwa i rozwiązywania problemów sieciowych niezbędne jest zrozumienie binarnej budowy pakietów. Wszystkie komunikaty TLS są hermetyzowane w strukturach zwanych rekordami TLS Record Layer. Rekord rozpoczyna się od 5-bajtowego nagłówka zawierającego ContentType, wersję protokołu oraz długość ładunku. Podprotokół Handshake odpowiada za najważniejszą fazę negocjacji i wymiany parametrów kryptograficznych. Pierwszym pakietem wysyłanym przez klienta jest ClientHello, zawierający 32-bajtową wartość losową Client Random.

Co ma wykonać student / grupa

W środowisku laboratoryjnym przygotowujesz plik skryptu tls_parser.py wykorzystujący standardowy moduł struct do rozpakowywania bajtów. Nawiązujesz gniazdo TCP z publicznym serwerem WWW lub przygotowujesz gotowy wektor szesnastkowy pakietu ClientHello. Skrypt odczytuje pierwsze 5 bajtów rekordu, identyfikując bajt typu zawartości o wartości 0x16 oznaczający protokół Handshake. Dekodujesz pole wersji rekordu (0x0301 lub 0x0303) oraz odczytujesz całkowitą długość danych z kolejnych dwóch bajtów.

Przechodzisz do wnętrza ładunku Handshake, sprawdzając czy HandshakeType ma wartość 0x01 odpowiadającą ClientHello. Wyodrębniasz 32 bajty pola Random i wyświetlasz je w postaci czytelnego ciągu heksadecymalnego.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik tls_parser.py i zaimportuj moduł struct oraz moduł socket.
  2. Przygotuj funkcję rozpakowującą nagłówek rekordu TLS: content_type, version, length = struct.unpack('!BHH', data[:5]).
  3. Sprawdź, czy content_type == 22 (Handshake). Wypisz wersję bazową i rozmiar ramki.
  4. Rozpakuj nagłówek Handshake: hs_type, hs_length = struct.unpack('!B3s', data[5:9]).
  5. Potwierdź, że hs_type == 1 (ClientHello).
  6. Wyodrębnij 32 bajty losowe: client_random = data[11:43].hex(). Wypisz uzyskany ciąg.
  7. Odczytaj długość Session ID: session_id_len = data[43], a następnie pomiń ten segment bajtów.
  8. Odczytaj 2-bajtową długość listy szyfrów: cipher_suites_len = struct.unpack('!H', data[offset:offset+2])[0].
  9. Zaimplementuj pętlę odczytującą kolejne 2-bajtowe kody ciphersuites: for i in range(0, cipher_suites_len, 2): code = struct.unpack('!H', ...).
  10. Wykonaj zrzut ekranu prezentujący zdekodowane pola Client Random, listę ciphersuites oraz nazwę domeny z SNI.

Kontrola zaliczenia (checklist):

  1. Uruchomiono parser handshake i zachowano log: rekordy ClientHello/ServerHello (wersja, random, cipher_suites, extensions TLV) sparsowane structem.
  2. Dołączono kod (własne 20–40 linii): nagłówek rekordu, dekompozycja Hello, tabela rozszerzeń (SNI/ALPN).
  3. Przeprowadzono test pozytywny (prawdziwy ClientHello parsuje) i negatywny (ucięty rekord — błąd długości zamiast śmieci).
  4. Opisano w 3–5 zdaniach: Record Layer, Client Random vs replay, TLV jako elastyczność TLS.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Szczegółowa znajomość binarnej budowy ramki TLS Record Layer oraz komunikatów fazy Handshake.
  • Zrozumienie roli pola Client Random w generowaniu kluczy sesyjnych i przeciwdziałaniu atakom powtórzeniowym.
  • Praktyczna umiejętność binarnego parsowania protokołów sieciowych w języku Python z użyciem modułu struct.
  • Świadomość struktury rozszerzeń TLV (Type-Length-Value) stanowiących fundament elastyczności standardu TLS.
Zadanie 4 - ilustracja
05/10
Zadanie 5. Symulacja protokołu uwierzytelniania Kerberos (KDC: Authentication Server i Ticket Granting Server) w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajdy 28, 29: architektura protokołu Kerberos, Key Distribution Center (KDC), Authentication Server (AS), Ticket Granting Server (TGS), bilety TGT i Service Ticket, symetryczne klucze sesyjne.
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest praktyczne zrozumienie działania protokołu uwierzytelniania w sieciach rozproszonych Kerberos v5. Student implementuje w języku Python kompletną symulację wymiany komunikatów pomiędzy Klientem, serwerem Authentication Server (AS), serwerem biletowym Ticket Granting Server (TGS) oraz Serwerem Usługi, badając rolę biletu TGT oraz kluczy sesyjnych.

Scenariusz – opis

W wielkich sieciach korporacyjnych i domenach Active Directory standardem uwierzytelniania jest protokół Kerberos. Kerberos rozwiązuje problem logowania w niezaufanej sieci bez konieczności przesyłania haseł użytkowników do serwerów aplikacji. Architektura opiera się na zaufanej trzeciej stronie zwanej Key Distribution Center KDC. W skład KDC wchodzą dwa logiczne moduły: serwer uwierzytelniania Authentication Server AS oraz serwer nadawania biletów Ticket Granting Server TGS. W pierwszym etapie klient uwierzytelnia się w AS za pomocą klucza wyprowadzonego ze swojego hasła. W odpowiedzi klient otrzymuje tymczasowy klucz sesyjny TGT oraz zaszyfrowany tajnym kluczem KDC bilet Ticket Granting Ticket TGT.

Co ma wykonać student / grupa

W środowisku laboratoryjnym tworzysz plik kerberos_sim.py modelujący interakcję czterech węzłów sieciowych. Definiujesz tajne klucze długoterminowe: klucz klienta wyprowadzony z hasła, klucz nadrzędny KDC oraz klucz serwera plików. Dla operacji kryptograficznych wykorzystujesz szyfr symetryczny AES-256 w trybie CBC lub GCM. Implementujesz etap 1 (AS Exchange): klient wysyła żądanie do AS, a AS generuje losowy klucz sesyjny K_Client_TGS.

AS tworzy bilet TGT zawierający tożsamość klienta, znacznik czasu oraz klucz K_Client_TGS, szyfrując całość kluczem KDC. AS odsyła pakiet do klienta, szyfrując klucz sesyjny kluczem hasła użytkownika, dzięki czemu klient może go odszyfrować.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik kerberos_sim.py i zaimportuj moduły: os, time, json z biblioteki standardowej oraz AESGCM z biblioteki cryptography.
  2. Zdefiniuj klucze długoterminowe uczestników: K_client = os.urandom(32), K_kdc = os.urandom(32), K_service = os.urandom(32).
  3. Napisz funkcję pomocniczą encrypt(key, dict_data) oraz decrypt(key, ciphertext) realizujące szyfrowanie AEAD.
  4. Zaimplementuj komunikat KRB_AS_REQ: klient wysyła nazwę użytkownika 'alice' oraz identyfikator realm 'LAB.LOCAL'.
  5. W module AS wygeneruj sesyjny klucz biletowy: K_client_tgs = os.urandom(32).
  6. Zbuduj strukturę biletu TGT: {'user': 'alice', 'k_session': K_client_tgs.hex(), 'expiry': time.time() + 36000}.
  7. Zaszyfruj bilet TGT kluczem K_kdc: enc_tgt = encrypt(K_kdc, tgt_data).
  8. Przygotuj odpowiedź KRB_AS_REP zaszyfrowaną kluczem K_client: {'k_session': K_client_tgs.hex(), 'tgt': enc_tgt}.
  9. Po stronie klienta odszyfruj odpowiedź i wyodrębnij sesyjny klucz K_client_tgs oraz zachowaj nienaruszony bilet TGT.
  10. Wykonaj zrzuty ekranu prezentujące komunikaty konsoli dla każdego etapu symulacji i umieść je w sprawozdaniu.

Kontrola zaliczenia (checklist):

  1. Uruchomiono symulację Kerberosa i zachowano log: AS→TGT→TGS→serwis, klucze sesyjne vs długoterminowe, authenticator ze znacznikiem czasu.
  2. Dołączono kod (własne 20–40 linii): KDC (AS+TGS), bilety, szyfrowanie sesyjne.
  3. Przeprowadzono test pozytywny (pełne SSO działa) i negatywny (stary authenticator / zły czas — odrzut replay).
  4. Opisano w 3–5 zdaniach: TGT jako SSO, authenticator vs replay, hierarchia kluczy.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Głębokie zrozumienie wieloetapowego procesu uwierzytelniania w protokole Kerberos v5.
  • Zrozumienie kluczowej roli biletu TGT w unikaniu wielokrotnego wprowadzania hasła przez użytkownika (model Single Sign-On).
  • Świadomość roli Authenticatora i znaczników czasu w uniemożliwianiu ataków powtórzeniowych (Replay Attacks).
  • Zrozumienie hierarchii kluczy: klucze długoterminowe uczestników vs krótkoterminowe klucze sesyjne.
Zadanie 5 - ilustracja
06/10
Zadanie 6. Kryptograficzna generacja i walidacja tokenów JWT (HS256 vs RS256) oraz test podatności 'alg: none' w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3 + jwt.io
Podstawa wykładowa: Część 5 - slajdy 32, 33: tokeny JSON Web Token, podpisy JWS, RFC 7519, porównanie algorytmu symetrycznego HS256 i asymetrycznego RS256, kryptoanalityczna podatność 'alg: none'.
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem ćwiczenia jest programowa implementacja mechanizmów generowania oraz kryptograficznej walidacji tokenów JWT w języku Python. Student implementuje weryfikację podpisów symetrycznych HS256 oraz asymetrycznych RS256, bada proces sprawdzania roszczeń czasowych oraz przeprowadza test bezpieczeństwa demonstrujący krytyczną podatność akceptacji niepodpisanego tokena z nagłówkiem 'alg: none'.

Scenariusz – opis

W architekturach REST API tokeny JWT stały się podstawowym nośnikiem tożsamości i uprawnień użytkowników. Wzorzec implementacyjny wymaga od serwera rygorystycznego sprawdzania kryptograficznego podpisu przed odczytaniem jakichkolwiek roszczeń. W algorytmie HS256 podpis jest wyliczany za pomocą funkcji HMAC ze wspólnym kluczem symetrycznym. W zastosowaniach rozproszonych preferowany jest algorytm asymetryczny RS256, w którym dostawca tożsamości podpisuje token kluczem prywatnym. Dzięki temu serwery aplikacji mogą weryfikować tokeny wyłącznie za pomocą publicznie dostępnego klucza RSA bez ryzyka wycieku uprawnień. Jedną z najsłynniejszych podatności w historii bibliotek webowych była podatność akceptacji tokenów z deklaracją algorytmu o wartości 'none'.

Co ma wykonać student / grupa

W pliku jwt_engine.py implementujesz własne funkcje kodujące i dekodujące format Base64URL bez używania gotowych bibliotek JWT. Tworzysz funkcję generującą poprawny token JWT z podpisem HMAC-SHA256 na podstawie podanego słownika nagłówka i ładunku. Implementujesz funkcję generującą token podpisany asymetrycznie kluczem prywatnym RSA przy użyciu algorytmu RS256. Tworzysz funkcję weryfikującą verify_jwt_hs256, która weryfikuje podpis, sprawdza format tokena oraz kontroluje pole czasu wygaśnięcia exp. Tworzysz drugą funkcję verify_jwt_rs256 weryfikującą podpis za pomocą klucza publicznego RSA. Następnie implementujesz podatną funkcję weryfikacyjną, która w pętli odczytuje pole alg i w przypadku wartości 'none' pomija sprawdzanie podpisu.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik jwt_engine.py i zaimportuj moduły: hmac, hashlib, json, base64, time oraz cryptography.
  2. Napisz funkcje pomocnicze: b64url_encode( data) oraz b64url_decode(str_data) poprawnie obsługujące padding '='.
  3. Zaimplementuj generator JWT z algorytmem HS256: generate_hs256( payload, secret).
  4. Wygeneruj parę kluczy RSA 2048-bit za pomocą modułu cryptography.hazmat.primitives.asymmetric.rsa.
  5. Zaimplementuj generator JWT z algorytmem RS256: generate_rs256( payload, private_key).
  6. Napisz funkcję weryfikacji RS256 sprawdzającą podpis kluczem publicznym oraz roszczenie exp: verify_rs256( token, pubkey).
  7. Napisz funkcję podatną vulnerable_verify( token, secret, pubkey), która dla header['alg'] == 'none' pomija sprawdzanie podpisu.
  8. Wygeneruj sfałszowany token z nagłówkiem: {'alg': 'none', 'typ': 'JWT'} oraz payloadem: {'user': 'attacker', 'role': 'admin'}.
  9. Zbuduj token ataku: token_malic = b64url_encode( header) + '.' + b64url_encode( payload) + '.'.
  10. Zapisz zrzuty ekranu z konsoli dokumentujące udany atak na podatny kod oraz jego skuteczne zablokowanie.

Kontrola zaliczenia (checklist):

  1. Uruchomiono generator/walidator JWT i zachowano log: HS256 i RS256 poprawne, atak alg:none odrzucony twardą listą algorytmów.
  2. Dołączono kod (własne 20–40 linii): weryfikacja podpisu, kontrola exp/iss/aud, wymuszenie oczekiwanego alg.
  3. Przeprowadzono test pozytywny (dobre tokeny przechodzą) i negatywny (none / podmieniony alg / wygasły — odrzut z powodem).
  4. Opisano w 3–5 zdaniach: symetryk vs asymetryk, plaga alg:none, nigdy nie ufaj headerowi klienta.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Zrozumienie mechanizmu kryptograficznego podpisywania tokenów JWT algorytmami symetrycznymi i asymetrycznymi.
  • Świadomość historycznej podatności 'alg: none' i przyczyn jej powszechnego występowania w bibliotekach webowych.
  • Praktyczna umiejętność implementacji rygorystycznej walidacji nagłówków kryptograficznych w języku Python.
  • Zrozumienie konieczności wymuszania oczekiwanego algorytmu po stronie serwera aplikacji wbrew deklaracjom klienta.
Zadanie 6 - ilustracja
07/10
Zadanie 7. Implementacja mechanizmu jednorazowych haseł opartych na czasie TOTP (RFC 6238) i integracja z kodem QR w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajdy 22, 23: wieloskładnikowe uwierzytelnianie (MFA), algorytmy HOTP (RFC 4226) i TOTP (RFC 6238), funkcja HMAC-SHA1, okno czasowe 30 sekund, dynamiczne obcinanie (Dynamic Truncation).
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest samodzielna implementacja algorytmu generowania i weryfikacji haseł jednorazowych TOTP od podstaw w języku Python zgodnie ze specyfikacją RFC 6238. Student implementuje algorytm dynamicznego obcinania Dynamic Truncation, oblicza kody w oknach czasowych 30 sekund, generuje format URI otpauth:// oraz testuje tolerancję na przesunięcia zegara systemowego.

Scenariusz – opis

Tradycyjne uwierzytelnianie jednoskładnikowe oparte wyłącznie na haśle jest wysoce podatne na wycieki i ataki phishingowe. Współczesnym standardem ochrony kont jest wieloskładnikowe uwierzytelnianie MFA, wykorzystujące drugi czynnik posiadania. Najpowszechniejszym rozwiązaniem drugiego składnika są 6-cyfrowe kody generowane przez aplikacje mobilne (np. Google Authenticator). Działają one w oparciu o algorytm TOTP Time-based One-Time Password ustandaryzowany w dokumencie RFC 6238. TOTP jest rozwinięciem algorytmu HOTP, w którym licznik zdarzeń został zastąpiony liczbą 30-sekundowych interwałów czasowych od epoki Uniksa.

Co ma wykonać student / grupa

W środowisku laboratoryjnym tworzysz plik totp_engine.py zawierający implementację algorytmów RFC 4226 i RFC 6238. Implementujesz funkcję generującą losowy klucz tajny Base32 o długości 160 bitów (20 bajtów). Definiujesz funkcję obliczającą licznik czasowy T jako liczbę całkowitą z dzielenia aktualnego czasu UTC przez długość kroku 30 sekund. Pakujesz wartość licznika T do 8-bajtowego ciągu binarnego w formacie Big-Endian za pomocą modułu struct.

Wyliczasz wartość funkcji HMAC z algorytmem SHA-1, przekazując tajny klucz oraz spakowany licznik czasowy. Implementujesz procedurę Dynamic Truncation: odczytujesz ostatni bajt skrótu HMAC i wyznaczasz przesunięcie offset jako 4 najmłodsze bity.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik totp_engine.py i zaimportuj moduły: hmac, hashlib, time, struct, base64.
  2. Zdefiniuj funkcję generate_secret(): wygeneruj 20 losowych bajtów i zwróć je w formacie base64.b32encode().
  3. Napisz funkcję hotp(secret_bytes, counter): oblicz HMAC-SHA1 z 8-bajtowego spakowanego licznika struct.pack('>Q', counter).
  4. Zaimplementuj w funkcji hotp procedurę dynamicznego obcinania: offset = hmac_result[-1] & 0x0F.
  5. Wyodrębnij 4 bajty: code_int = struct.unpack('>I', hmac_result[ offset:offset+4])[0] & 0x7FFFFFFF.
  6. Zwróć sformatowany kod: f'{code_int % 1000000:06d}'.
  7. Napisz funkcję totp(secret_b32, time_step=30): oblicz counter = int(time.time() / time_step) i wywołaj hotp.
  8. Przetestuj implementację na oficjalnych wektorach testowych RFC 6238 dla podanych znaczników czasu.
  9. Upewnij się, że dla znacznika czasu T=59s i zadanego klucza testowego funkcja zwraca poprawny wektor z RFC.
  10. Zapisz zrzut ekranu działania pętli monitorującej oraz dołącz kod skryptu do sprawozdania.

Kontrola zaliczenia (checklist):

  1. Uruchomiono TOTP i zachowano log: kody dla 3 okien 30 s zgodne z RFC 6238 (wektory), tolerancja ±1 okno, QR do aplikacji.
  2. Dołączono kod (własne 20–40 linii): HMAC-SHA1, dynamic truncation, base32 secret, generator QR.
  3. Przeprowadzono test pozytywny (wektor RFC przechodzi) i negatywny (zły czas/sekret — odrzut, dryf opisany).
  4. Opisano w 3–5 zdaniach: HOTP→TOTP, truncation do PIN, okna/tolerancja, MFA z QR.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Głębokie zrozumienie matematycznych podstaw algorytmów HOTP (RFC 4226) oraz TOTP (RFC 6238).
  • Praktyczna znajomość procedury Dynamic Truncation przekształcającej skrót kryptograficzny w krótki kod PIN.
  • Zrozumienie znaczenia okien czasowych (30s) oraz tolerancji zegarowej w implementacjach serwerowych.
  • Umiejętność integracji algorytmów kryptograficznych z ekosystemem aplikacji uwierzytelniania wieloskładnikowego MFA.
Zadanie 7 - ilustracja
08/10
Zadanie 8. Podpisywanie i weryfikacja wiadomości pocztowych w standardzie S/MIME oraz weryfikacja sygnatury DKIM w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajdy 36, 37, 41: bezpieczna poczta elektroniczna, standard S/MIME (RFC 8551), struktury CMS/PKCS#7, sygnatury DKIM (RFC 6376), kanonizacja nagłówków i treści.
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest praktyczne zbadanie dwóch kluczowych technologii kryptograficznych zabezpieczających pocztę elektroniczną: standardu S/MIME oraz protokołu DKIM. Student implementuje w języku Python podpisywanie wiadomości e-mail certyfikatem X.509 w formacie S/MIME oraz weryfikuje kryptograficzny podpis DKIM-Signature pobierając publiczny klucz nadawcy.

Scenariusz – opis

Poczta elektroniczna pozostaje jednym z najbardziej wrażliwych kanałów komunikacji biznesowej i urzędowej. Dla zapewnienia integralności i niezaprzeczalności przesyłanych wiadomości stosuje się dwa odrębne podejścia kryptograficzne. Pierwsze z nich, S/MIME, działa na poziomie użytkownika końcowego (end-to-end), zabezpieczając treść za pomocą certyfikatu osobistego X.509. Podpis S/MIME jest hermetyzowany w strukturze Cryptographic Message Syntax CMS w formacie wieloczęściowym multipart/signed. Drugie rozwiązanie, DKIM DomainKeys Identified Mail, działa na poziomie serwerów pocztowych infrastruktury domeny. Serwer nadawczy sygnuje nagłówki i treść wiadomości asymetrycznym kluczem prywatnym domeny, umieszczając nagłówek DKIM-Signature.

Co ma wykonać student / grupa

W środowisku laboratoryjnym przygotowujesz plik email_crypto.py z modułami do obsługi wiadomości MIME i kryptografii. Tworzysz przykładową wiadomość e-mail za pomocą standardowego modułu email.message. Wczytujesz certyfikat osobisty oraz klucz prywatny wygenerowany we wcześniejszych ćwiczeniach. Za pomocą biblioteki cryptography lub OpenSSL tworzysz strukturę CMS PKCS#7 podpisującą treść wiadomości z algorytmem SHA-256.

Konstruujesz poprawny obiekt MIME o typie multipart/signed z parametrem protocol = application/pkcs7-signature. Sprawdzasz weryfikację podpisu S/MIME, odczytując certyfikat podpisujący oraz weryfikując integralność tekstu jawnego.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik email_crypto.py i zaimportuj moduły: email, hashlib, base64 oraz cryptography.
  2. Zbuduj prostą wiadomość e-mail: msg = EmailMessage(), dodając nagłówki From, To, Subject oraz treść.
  3. Wczytaj certyfikat użytkownika i klucz prywatny z plików PEM.
  4. Przygotuj funkcję tworzącą podpis CMS: uzyj PKCS7SignatureBuilder lub wywołaj polecenie openssl smime -sign.
  5. Zapisz podpisaną wiadomość do pliku wiadomosc_smime.eml.
  6. Wyświetl zawartość pliku eml, identyfikując nagłówek Content-Type: multipart/signed oraz załącznik smime.p7s.
  7. Zweryfikuj integralność wiadomości S/MIME: sprawdź poprawność podpisu względem certyfikatu wystawcy.
  8. Przygotuj przykładowy nagłówek DKIM-Signature zawierający tagi: v=1; a=rsa-sha256; c=relaxed/relaxed; d=domena.pl; s=s2024; bh=...; b=...
  9. Napisz funkcję kanonizacji treści canonicalize_body_relaxed(body_bytes), usuwającą spacje na końcach linii i redukującą puste wiersze.
  10. Zapisz zrzuty ekranu prezentujące strukturę pliku S/MIME oraz raport z weryfikacji skrótu i podpisu DKIM.

Kontrola zaliczenia (checklist):

  1. Uruchomiono podpis S/MIME i weryfikację DKIM i zachowano log: multipart/signed (CMS/PKCS#7) poprawny oraz DKIM pass/fail po kanonizacji.
  2. Dołączono kod (własne 20–40 linii): podpisywanie certyfikatem, parser DKIM-Signature, kanonizacja header/body.
  3. Przeprowadzono test pozytywny (poprawne przechodzą) i negatywny (zmieniona treść/MTA bez kanonizacji — fail z diagnozą).
  4. Opisano w 3–5 zdaniach: podpis użytkownika vs domeny, CMS, kanonizacja jako odporność na MTA.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Zrozumienie fundamentalnych różnic pomiędzy podpisem użytkownika S/MIME a podpisem domeny DKIM.
  • Praktyczna znajomość budowy wiadomości multipart/signed oraz struktur CMS / PKCS#7.
  • Zrozumienie roli procesu kanonizacji nagłówków i treści w zapewnianiu odporności podpisów DKIM na modyfikacje MTA.
  • Umiejętność samodzielnej weryfikacji kryptograficznej poszczególnych składowych nagłówka DKIM-Signature.
Zadanie 8 - ilustracja
09/10
Zadanie 9. Kryptoanalityczna walidacja łańcucha DNSSEC (rekordy DNSKEY, DS, RRSIG) od roota do domeny w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajd 40: ochrona integralności DNS przez DNSSEC (RFC 4033-4035), rekordy DNSKEY (ZSK i KSK), RRSIG (podpis cyfrowy), DS (Delegation Signer), łańcuch zaufania do roota.
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest praktyczne prześledzenie i weryfikacja kryptograficznego łańcucha zaufania DNSSEC od strefy głównej root aż do domeny końcowej. Student bada strukturę rekordów DNSKEY, DS oraz RRSIG, implementuje w języku Python weryfikację skrótu rekordu DS względem klucza KSK oraz weryfikuje podpis cyfrowy rekordu adresowego A za pomocą klucza ZSK.

Scenariusz – opis

Klasyczny system nazw domenowych DNS przesyła zapytania i odpowiedzi otwartym tekstem przez protokół UDP. Brak uwierzytelniania umożliwił ataki zatruwania pamięci podręcznej DNS Cache Poisoning, kierujące ruch użytkowników na fałszywe serwery. Odpowiedzią na to zagrożenie jest rozszerzenie bezpieczeństwa DNSSEC ustandaryzowane w dokumentach RFC 4033 do 4035. DNSSEC nie szyfruje zapytań w celu zapewnienia poufności, lecz gwarantuje autentyczność i integralność odpowiedzi poprzez podpisy cyfrowe. W każdej zabezpieczonej strefie rekordy są grupowane w zestawy RRSET i podpisywane kluczem strefowym ZSK Zone Signing Key. Podpis cyfrowy każdego zestawu rekordów jest publikowany w powiązanym rekordzie RRSIG.

Co ma wykonać student / grupa

W terminalu JSLinux lub w środowisku Pythona instalujesz moduł dnspython do odpytywania serwerów nazw. Wybierasz publiczną domenę posiadającą poprawną konfigurację DNSSEC, na przykład gov.pl lub iana.org. Wysyłasz zapytanie o rekord adresowy A badanej domeny z włączoną flagą DO DNSSEC OK. Odbierasz zestaw rekordów A oraz towarzyszący mu rekord podpisu cyfrowego RRSIG.

Odpytujesz strefę o rekordy DNSKEY, identyfikując klucz ZSK (flaga 256) oraz klucz KSK (flaga 257). Implementujesz funkcję wyliczającą skrót SHA-256 z rekordu KSK strefy badanej domeny.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik dnssec_verify.py i zaimportuj moduły: dns.resolver, dns.dnssec, hashlib.
  2. Skonfiguruj resolver DNS z włączoną obsługą DNSSEC: res = dns.resolver.Resolver(); res.use_edns(0, dns.flags.DO, 4096).
  3. Pobierz rekord A oraz rekord RRSIG dla domeny: q = res.resolve('iana.org', 'A').
  4. Wypisz zawartość rekordu A oraz pola rekordu RRSIG: algorytm, etykiety, daty ważności i wartość podpisu.
  5. Pobierz rekordy DNSKEY strefy: dnskey_rr = res.resolve('iana.org', 'DNSKEY').
  6. Zidentyfikuj klucze: znajdź klucz z flagą 256 (ZSK) oraz klucz z flagą 257 (KSK).
  7. Pobierz rekord DS ze strefy nadrzędnej: ds_rr = res.resolve('iana.org', 'DS').
  8. Napisz funkcję obliczającą skrót KSK: wylicz SHA-256 z danych kanonicznych klucza KSK.
  9. Porównaj wyliczony skrót z polem digest rekordu DS i potwierdź dopasowanie: print('Dopasowanie KSK do rekordu DS: ZGODNE').
  10. Zapisz zrzuty ekranu z konsoli oraz dołącz kod skryptu do sprawozdania laboratoryjnego.

Kontrola zaliczenia (checklist):

  1. Uruchomiono walidator DNSSEC i zachowano log: łańcuch root→domena (DNSKEY, DS-hash, RRSIG verify) dla min. 1 domeny podpisanej.
  2. Dołączono kod (własne 20–40 linii): pobieranie rekordów, hash DS, weryfikacja RRSIG.
  3. Przeprowadzono test pozytywny (podpisana domena przechodzi) i negatywny (zerwany DS / wygasły RRSIG — odrzut).
  4. Opisano w 3–5 zdaniach: ZSK vs KSK, DS jako kotwica między strefami, koniec cache poisoning.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Zrozumienie architektury bezpieczeństwa rozszerzenia DNSSEC i eliminacji zagrożenia DNS Cache Poisoning.
  • Praktyczna znajomość ról kluczy ZSK (Zone Signing Key) oraz KSK (Key Signing Key).
  • Zrozumienie kryptograficznej funkcji rekordu DS (Delegation Signer) jako kotwicy zaufania pomiędzy strefami.
  • Umiejętność programowej weryfikacji rekordów i podpisów RRSIG z wykorzystaniem dedykowanych bibliotek sieciowych.
Zadanie 9 - ilustracja
10/10
Zadanie 10. Skrypt audytujący i profilujący bezpieczeństwo konfiguracji serwera TLS (szyfry, PFS, nagłówki HSTS) w Pythonie
🖥️ Wymagane środowisko:
System: Windows + JSLinux Alpine (Python 3)
Oprogramowanie: przeglądarka + OpenSSL + Python 3
Podstawa wykładowa: Część 5 - slajdy 16, 21, 44, 45, 47: audyt konfiguracji TLS, profilowanie serwera, eliminacja podatnych szyfrów, Perfect Forward Secrecy (PFS), nagłówki HTTP Strict Transport Security (HSTS).
Szacowany czas: ~80-100 min | trudność M | Artefakt: 1 plik/log/zrzut | Starter: LAB5_startery/validator_szkielet.py, acme_szkielet.py

Cel

Celem zadania jest zaprojektowanie i implementacja w języku Python kompleksowego skryptu audytującego konfigurację kryptograficzną serwerów WWW. Student bada obsługiwane wersje protokołów (TLS 1.2, TLS 1.3), sprawdza obecność bezpiecznych zestawów szyfrów gwarantujących Perfect Forward Secrecy, wykrywa przestarzałe algorytmy oraz weryfikuje nagłówek ochronny HSTS.

Scenariusz – opis

Samo zainstalowanie ważnego certyfikatu X.509 na serwerze WWW nie gwarantuje jeszcze pełnego bezpieczeństwa transmisji. Kluczowe znaczenie ma poprawna konfiguracja parametrów silnika TLS po stronie serwera aplikacji. Nieprawidłowo skonfigurowany serwer może dopuszczać podatne wersje protokołów (TLS 1.0, TLS 1.1) lub przestarzałe szyfry blokowe. Współczesne standardy bezpieczeństwa wymagają bezwzględnego stosowania mechanizmu Perfect Forward Secrecy PFS opartego na ECDHE. PFS gwarantuje, że ewentualne przejęcie klucza prywatnego serwera w przyszłości nie pozwoli na odszyfrowanie nagranych wcześniej sesji. Ponadto aplikacje muszą wymuszać szyfrowanie za pomocą nagłówka HTTP Strict Transport Security HSTS zdefiniowanego w RFC 6797.

Co ma wykonać student / grupa

W środowisku laboratoryjnym tworzysz plik tls_auditor.py wykorzystujący standardowe moduły ssl oraz socket. Definiujesz listę testowych konfiguracji SSLContext obejmujących wersje protokołów od przestarzałych do najnowszych. Implementujesz funkcję testującą obsługę protokołów: sprawdzasz czy serwer akceptuje połączenia TLS 1.0, TLS 1.1, TLS 1.2 oraz TLS 1.3. Dla udanych połączeń odpytujesz gniazdo o wynegocjowany zestaw szyfrów oraz parametry asymetrycznej wymiany kluczy.

Sprawdzasz, czy serwer wymusza szyfry zapewniające Perfect Forward Secrecy (obecność algorytmu ECDHE). Testujesz próbę nawiązania sesji z wymuszeniem wycofanych i słabych szyfrów (np.

Przykładowe kroki do wykonania jako sugestia

  1. Utwórz plik tls_auditor.py i zaimportuj moduły: ssl, socket, urllib.request, json.
  2. Zdefiniuj funkcję test_tls_version( hostname, port, version): skonfiguruj ssl.SSLContext i spróbuj nawiązać połączenie.
  3. Przetestuj obsługę protokołów: sprawdź kolejno TLSv1, TLSv1_1, TLSv1_2 oraz TLSv1_3.
  4. Zarejestruj, które wersje protokołów zostały zaakceptowane przez badany serwer.
  5. Dla protokołu TLS 1.2 wyodrębnij wynegocjowany ciphersuite za pomocą metody sslobj.cipher().
  6. Sprawdź, czy nazwa szyfru zawiera ciąg 'ECDHE', potwierdzając właściwość Perfect Forward Secrecy.
  7. Napisz funkcję sprawdzającą podatne szyfry: spróbuj wymusić zestaw ciphers='RC4:3DES:DES' i upewnij się, że serwer odrzuca próbę.
  8. Napisz funkcję badającą nagłówki HTTP: wyślij żądanie urllib.request.Request(f'https://{hostname}') z metodą HEAD.
  9. Odczytaj nagłówek 'Strict-Transport-Security' z odpowiedzi serwera.
  10. Zapisz zrzut ekranu z wykonania audytu oraz dołącz wygenerowany plik JSON do sprawozdania laboratoryjnego.

Kontrola zaliczenia (checklist):

  1. Uruchomiono audytor TLS i zachowano raport: wersje (odrzut SSLv3/TLS1.0/1.1), PFS w cipherach, HSTS, pełny werdykt A–F dla min. 2 hostów.
  2. Dołączono kod (własne 20–40 linii): sondowanie wersji, parser cipherów, kontrola nagłówków.
  3. Przeprowadzono test pozytywny (nowoczesny host wysoko) i negatywny (celowo słaby profil wykryty i opisany).
  4. Opisano w 3–5 zdaniach: PFS jako ochrona historii, przestarzałe protokoły, HSTS vs SSL stripping.

Wariant offline (fallback): Brak biblioteki cryptography: standardowe hashlib/json + openssl CLI; testy na wektorach z RFC w starterze bez sieci; dołącz kod (szkielet + własne 20–40 linii) i log z konsoli.

Sugerowane wnioski i podsumowanie - co student ma osiągnąć

Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:

  • Praktyczna umiejętność programowego audytowania konfiguracji TLS serwerów za pomocą języka Python.
  • Zrozumienie krytycznej roli mechanizmu Perfect Forward Secrecy (PFS) w ochronie nagranych danych historycznych.
  • Świadomość zagrożeń wynikających ze wspierania przestarzałych wersji protokołów SSLv3, TLS 1.0 i TLS 1.1.
  • Znajomość działania nagłówka HSTS oraz jego roli w uniemożliwianiu ataków typu SSL Stripping.
Zadanie 10 - ilustracja
Podgląd