Materiał do egzaminu INF.11 — projektowanie, SQL, administracja, uprawnienia, szyfrowanie, SQL Injection i NoSQL

Bazy danych i SQL

Projektowanie i normalizacja, tworzenie struktur i zarządzanie danymi, złożone zapytania z pomocą AI, administracja serwerem i kopie zapasowe, bezpieczeństwo (uprawnienia, szyfrowanie, audyt), SQL Injection oraz bazy nierelacyjne.

38lekcji
7zadań praktycznych
76pytań „Sprawdź się”
Spis treści

Kurs łączy materiał przedmiotów „Bazy danych” i „Projektowanie i administracja relacyjnymi bazami danych”. Zaczyna od modelu relacyjnego i projektowania, przechodzi przez SQL i administrację, a kończy na bezpieczeństwie: uprawnieniach, szyfrowaniu, audycie, SQL Injection i bazach NoSQL. Przykłady są zapisane w składni MariaDB/MySQL (z uwagami o PostgreSQL), a w części o bazach nierelacyjnych w MongoDB.

Kurs jest podzielony na siedem części. Każda lekcja kończy się krótkimi pytaniami „Sprawdź się” ze schowaną odpowiedzią, a każda część zadaniem praktycznym. Ćwiczenia wykonuj na własnych bazach testowych, nigdy na cudzych systemach bez zgody właściciela.

Część A

Projektowanie relacyjnych baz danych

Tabele, klucze, typy danych, więzy, diagramy ERD, normalizacja, separacja danych wrażliwych, transakcje i ACID.

Lekcja 1 · Część A

Podstawy relacyjnych baz danych

Baza danych to uporządkowany zbiór danych, a system zarządzania bazą danych (SZBD) to program, który je przechowuje, udostępnia i chroni (np. MariaDB, MySQL, PostgreSQL, SQL Server, Oracle). W modelu relacyjnym dane są zapisane w tabelach powiązanych relacjami.

PojęcieZnaczeniePrzykład
Tabela (relacja)zbiór danych o jednym rodzaju obiektówuczniowie
Wiersz (rekord, krotka)jeden egzemplarz obiektuAnna Kowalska, klasa 2A
Kolumna (atrybut, pole)jedna cecha obiektu o określonym typienazwisko typu tekstowego
Klucz główny (PK)kolumna (lub zestaw) jednoznacznie identyfikująca wiersz; unikalny i niepustyid
Klucz obcy (FK)kolumna wskazująca klucz główny innej tabeli; tworzy relacjęuczniowie.klasa_id → klasy.id
Indeksstruktura przyspieszająca wyszukiwanieindeks na nazwisko
Widokzapisane zapytanie widziane jak tabelav_uczniowie
Transakcjagrupa operacji wykonywanych w całości albo wcaleprzelew: zdjęcie i dopisanie środków

Rodzaje poleceń SQL

GrupaZadaniePolecenia
DDLdefiniowanie strukturCREATE, ALTER, DROP, TRUNCATE
DMLzmiana danychINSERT, UPDATE, DELETE
DQLodczyt danychSELECT
DCLuprawnieniaGRANT, REVOKE
TCLtransakcjeSTART TRANSACTION, COMMIT, ROLLBACK
Dialekty SQL

SQL jest standardem, ale każdy SZBD ma własne rozszerzenia. W kursie przykłady są zapisane w składni MariaDB/MySQL, a tam, gdzie różni się PostgreSQL, jest to zaznaczone.

Sprawdź się — zadanie 1

Czym różni się klucz główny od klucza obcego?

Pokaż przykładową odpowiedź

Klucz główny jednoznacznie identyfikuje wiersz w swojej tabeli (unikalny, niepusty). Klucz obcy to kolumna, która wskazuje klucz główny innej tabeli i tworzy powiązanie między tabelami.

Sprawdź się — zadanie 2

Do której grupy poleceń należy GRANT?

Pokaż przykładową odpowiedź

Do DCL (język kontroli dostępu), bo nadaje uprawnienia użytkownikom i rolom.

Lekcja 2 · Część A

Typy danych i więzy integralności

Dobór typu danych wpływa na poprawność, miejsce i bezpieczeństwo. Za mały typ powoduje błędy przepełnienia, za duży marnuje miejsce i obniża wydajność.

DaneDobry typUwagi
liczby całkowiteTINYINT, SMALLINT, INT, BIGINTINT signed: do 2 147 483 647; UNSIGNED podwaja zakres dodatni
kwoty pieniężneDECIMAL(10,2)nigdy FLOAT (błędy zaokrągleń)
tekstVARCHAR(n), CHAR(n), TEXTogranicz długość n do potrzeb
data i czasDATE, DATETIME, TIMESTAMPnie przechowuj dat jako tekstu
wartość logicznaBOOLEAN (TINYINT(1))
wartość z listyENUM lub tabela słownikowatabela słownikowa łatwiej się rozwija
Przepełnienie i tryb ścisły

W trybie nieścisłym baza potrafi po cichu obciąć zbyt długi tekst lub zaokrąglić liczbę poza zakresem. Włącz tryb ścisły (sql_mode z STRICT_TRANS_TABLES), aby błędne dane powodowały błąd, a nie były zmieniane.

Więzy integralności

WięzyDziałanie
PRIMARY KEYunikalna, niepusta identyfikacja wiersza
FOREIGN KEYwartość musi istnieć w tabeli nadrzędnej
UNIQUEwartości w kolumnie nie mogą się powtarzać
NOT NULLkolumna nie może być pusta
CHECKwartość musi spełniać warunek
DEFAULTwartość domyślna
Przykład tabeli z więzami
CREATE TABLE klasy (
  id    INT UNSIGNED NOT NULL AUTO_INCREMENT,
  nazwa VARCHAR(10)  NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY uq_klasy_nazwa (nazwa)
) ENGINE=InnoDB;

CREATE TABLE uczniowie (
  id        INT UNSIGNED NOT NULL AUTO_INCREMENT,
  imie      VARCHAR(50)  NOT NULL,
  nazwisko  VARCHAR(80)  NOT NULL,
  email     VARCHAR(120) NOT NULL,
  klasa_id  INT UNSIGNED NOT NULL,
  utworzono DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  UNIQUE KEY uq_uczniowie_email (email),
  CONSTRAINT fk_uczniowie_klasa FOREIGN KEY (klasa_id) REFERENCES klasy (id)
) ENGINE=InnoDB;
Sprawdź się — zadanie 1

Dlaczego kwoty pieniężne przechowuje się jako DECIMAL, a nie FLOAT?

Pokaż przykładową odpowiedź

FLOAT zapisuje liczby przybliżone, więc pojawiają się błędy zaokrągleń. DECIMAL przechowuje dokładne wartości dziesiętne, co jest konieczne w rozliczeniach.

Sprawdź się — zadanie 2

Co robi ograniczenie CHECK?

Pokaż przykładową odpowiedź

Wymusza, aby wartość w kolumnie spełniała podany warunek (np. ocena od 1 do 6). Wstawienie lub zmiana na wartość spoza warunku kończy się błędem.

Lekcja 3 · Część A

Modelowanie: diagramy związków encji i rodzaje relacji

Projekt bazy zaczyna się od diagramu związków encji (ERD): ustalamy encje (obiekty, np. uczeń, klasa, przedmiot), ich atrybuty oraz relacje między nimi. Dopiero potem tworzymy tabele.

RelacjaZnaczeniePrzykładJak ją zapisać w tabelach
1:1jednemu wierszowi odpowiada jeden wierszuczeń i jego dane wrażliweFK z ograniczeniem UNIQUE lub wspólny klucz
1:Njeden wiersz ma wiele powiązanychjedna klasa, wielu uczniówFK po stronie „wiele” (uczniowie.klasa_id)
N:Mwiele do wieluuczniowie i przedmiotytabela łącząca z dwoma kluczami obcymi
Schemat tekstowy
KLASY (1) ----< UCZNIOWIE (N)

UCZNIOWIE (N) >----< PRZEDMIOTY (M)
   realizowane przez tabelę łączącą OCENY:
   OCENY(id, uczen_id -> UCZNIOWIE, przedmiot_id -> PRZEDMIOTY, ocena, data)
  • w tabeli łączącej klucz główny bywa złożony (uczen_id + przedmiot_id + data) lub sztuczny (id),
  • nazwy tabel i kolumn powinny być spójne i opisowe,
  • każdy diagram opisuje kardynalność (1, N) i obowiązkowość (czy relacja musi istnieć),
  • diagram jest dokumentacją: aktualizuj go razem ze schematem.
Sprawdź się — zadanie 1

Jak zapiszesz relację wiele do wielu między uczniami a kołami zainteresowań?

Pokaż przykładową odpowiedź

Przez tabelę łączącą (np. czlonkostwa) z kluczami obcymi do uczniowie i kola. Para (uczeń, koło) jest wierszem tabeli łączącej.

Sprawdź się — zadanie 2

Gdzie umieszcza się klucz obcy w relacji 1:N?

Pokaż przykładową odpowiedź

Po stronie „wiele”, czyli w tabeli, której wiersze należą do jednego wiersza tabeli nadrzędnej (np. uczniowie.klasa_id).

Lekcja 4 · Część A

Normalizacja: eliminacja redundancji

Normalizacja to porządkowanie tabel tak, aby ograniczyć redundancję (powtarzanie tych samych danych) oraz anomalie: wstawiania, aktualizacji i usuwania. Kolejne postacie normalne dodają coraz ostrzejsze wymagania.

PostaćWymaganieNaruszenie (przykład)
1NFwartości atomowe, brak powtarzających się grup kolumnkolumna telefony z listą „111, 222, 333”
2NF1NF i brak zależności od części klucza złożonegow tabeli (zamówienie, produkt) nazwa produktu zależy tylko od produktu
3NF2NF i brak zależności przechodnich (kolumna niekluczowa zależy tylko od klucza)adres klienta w tabeli zamówień zależy od klienta, a nie od zamówienia
Przed normalizacją i po
-- Przed: powtarzają się dane klienta i produktu
zamowienia(id_zam, klient, adres_klienta, produkt, cena, ilosc)

-- Po (3NF):
klienci(id_klienta, nazwa, adres)
produkty(id_produktu, nazwa, cena)
zamowienia(id_zam, id_klienta -> klienci, data)
pozycje_zamowienia(id_zam -> zamowienia, id_produktu -> produkty, ilosc)

Korzyść: adres klienta zapisany raz, więc jego zmiana to jedna aktualizacja, a usunięcie zamówienia nie niszczy danych o kliencie. Denormalizację (świadome powtórzenia) stosuje się czasem dla wydajności raportów, ale kosztem spójności i złożoności.

Sprawdź się — zadanie 1

Jaki problem rozwiązuje przeniesienie adresu klienta z tabeli zamówień do tabeli klientów?

Pokaż przykładową odpowiedź

Eliminuje redundancję: adres jest zapisany raz. Unika się anomalii aktualizacji (zmiana adresu w jednym miejscu) i usuwania (usunięcie zamówienia nie usuwa danych klienta).

Sprawdź się — zadanie 2

Co oznacza, że tabela jest w pierwszej postaci normalnej (1NF)?

Pokaż przykładową odpowiedź

Wszystkie wartości są atomowe (niepodzielne), a w tabeli nie ma powtarzających się grup kolumn ani list w jednym polu.

Lekcja 5 · Część A

Separacja danych wrażliwych i minimalizacja danych

Dane wrażliwe (PESEL, adres, dane zdrowotne, hasła) wymagają osobnej ochrony. Projekt schematu powinien oddzielić je od danych zwykłych i ograniczyć ich dostępność.

Rodzaj separacjiOpisPrzykład
Logicznaosobne tabele lub schematy, osobne uprawnieniatabela dane_osobowe w osobnej bazie lub schemacie
Fizycznaosobny serwer, dysk lub przestrzeń tabelszyfrowany wolumen tylko dla danych wrażliwych
Widokiudostępnianie tylko wybranych kolumnv_uczniowie bez adresu i PESEL
Szyfrowanie / tokenizacjadane zapisane w postaci zaszyfrowanej lub zastąpione tokenemszyfrowanie kolumny po stronie aplikacji
Osobna baza na dane wrażliwe i widok bez wrażliwych kolumn
CREATE DATABASE szkola_wrazliwe;
CREATE TABLE szkola_wrazliwe.dane_osobowe (
  uczen_id INT UNSIGNED NOT NULL PRIMARY KEY,
  pesel    CHAR(11)     NOT NULL,
  adres    VARCHAR(200) NOT NULL
) ENGINE=InnoDB;

CREATE VIEW szkola.v_uczniowie AS
  SELECT id, imie, nazwisko, klasa_id FROM szkola.uczniowie;
Zasady

Minimalizacja danych: przechowuj tylko to, co potrzebne, i tak długo, jak trzeba (zgodność z RODO). Hasła zapisuj jako skróty Argon2/bcrypt z solą, nigdy jawnie ani szyfrowane odwracalnie. Dostęp do danych wrażliwych nadawaj nielicznym rolom.

Sprawdź się — zadanie 1

Po co tworzy się widok pomijający kolumny z danymi wrażliwymi?

Pokaż przykładową odpowiedź

Aby użytkownicy i aplikacje, które nie potrzebują tych danych, miały dostęp tylko do bezpiecznego podzbioru kolumn. Zmniejsza to ryzyko wycieku i ułatwia nadawanie uprawnień.

Sprawdź się — zadanie 2

Dlaczego hasła użytkowników zapisuje się jako skróty, a nie szyfruje?

Pokaż przykładową odpowiedź

Szyfrowanie jest odwracalne: kto zdobędzie klucz, odczyta wszystkie hasła. Skrót z solą (Argon2, bcrypt) jest jednokierunkowy, więc wyciek bazy nie ujawnia haseł wprost.

Lekcja 6 · Część A

Transakcje, ACID, indeksowanie i audytowalność

Transakcja to zestaw operacji, które wykonują się jako jedna całość. Poprawne transakcje spełniają zasady ACID:

LiteraZasadaZnaczenie
AAtomowość (Atomicity)wykonują się wszystkie operacje albo żadna
CSpójność (Consistency)po transakcji dane spełniają wszystkie więzy
IIzolacja (Isolation)równoległe transakcje nie zakłócają się wzajemnie
DTrwałość (Durability)zatwierdzone zmiany przetrwają awarię

Klasyczny przykład: przelew. Zdjęcie kwoty z jednego konta i dopisanie na drugie musi być jedną transakcją, bo awaria po pierwszej operacji zniszczyłaby spójność danych.

Indeksowanie i partycjonowanie (pojęcia)

  • indeks przyspiesza wyszukiwanie i sortowanie, ale spowalnia zapis i zajmuje miejsce,
  • partycjonowanie dzieli dużą tabelę na części (np. po miesiącach), co ułatwia zarządzanie i archiwizację,
  • audytowalność: możliwość ustalenia, kto, co i kiedy zmienił (kolumny audytowe, tabele historii, logi).
Sprawdź się — zadanie 1

Co oznacza atomowość transakcji?

Pokaż przykładową odpowiedź

Że wszystkie jej operacje wykonują się razem albo żadna. W razie błędu wszystkie zmiany są wycofywane, więc dane nie zostają w stanie pośrednim.

Sprawdź się — zadanie 2

Dlaczego nie warto zakładać indeksu na każdej kolumnie?

Pokaż przykładową odpowiedź

Każdy indeks zajmuje miejsce i musi być aktualizowany przy zapisie, więc spowalnia INSERT, UPDATE i DELETE. Indeksy zakłada się na kolumnach często używanych do wyszukiwania, łączenia i sortowania.

Zadanie praktyczne

Projekt bazy danych dziennika szkolnego

Szacowany czas: 60 minZakres: Lekcje 1–6Forma: diagram ERD i skrypt SQL

Zadanie

Zaprojektuj bazę danych uproszczonego dziennika elektronicznego z uwzględnieniem bezpieczeństwa danych.

Założenia

  • Encje: uczniowie, klasy, nauczyciele, przedmioty, oceny oraz dane osobowe uczniów (PESEL, adres).
  • Narysuj diagram ERD z relacjami 1:N i N:M (tabela łącząca) i sprawdź, czy schemat jest w 3NF.
  • Dobierz typy danych i więzy: klucze główne i obce, UNIQUE, NOT NULL, CHECK (ocena od 1 do 6).
  • Oddziel dane wrażliwe do osobnej tabeli lub schematu i przygotuj widok bez tych danych.
  • Napisz skrypt CREATE TABLE i krótko opisz (3–4 zdania), jak projekt chroni dane i wspiera audyt zmian.

Ocenie podlegać będzie

  • poprawność ERD i relacji,
  • normalizacja do 3NF,
  • dobór typów i więzów,
  • separacja danych wrażliwych,
  • działający skrypt SQL.
Wskazówki
  • Tabela łącząca dla uczniów i przedmiotów może być tabelą oceny.
  • Pamiętaj o kolejności tworzenia tabel (najpierw nadrzędne).
  • Wróć do lekcji 2, 4 i 5.

Część B

SQL: tworzenie struktur i zarządzanie danymi

DDL, indeksy i widoki, klucze obce i kaskady, bezpieczne wstawianie, zmiana i usuwanie danych, transakcje, maskowanie i migracje schematu.

Lekcja 7 · Część B

Tworzenie i modyfikowanie struktur: DDL

Podstawowe polecenia
CREATE DATABASE szkola CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE szkola;

ALTER TABLE uczniowie ADD COLUMN telefon VARCHAR(20) NULL AFTER email;
ALTER TABLE uczniowie MODIFY COLUMN telefon VARCHAR(25) NULL;
ALTER TABLE uczniowie DROP COLUMN telefon;

TRUNCATE TABLE tymczasowe;       -- usuwa wszystkie wiersze, nie da się wycofać w wielu SZBD
DROP TABLE tymczasowe;           -- usuwa tabelę wraz z danymi
DROP DATABASE IF EXISTS testowa;

Izolowane schematy i przestrzenie tabel. Osobne schematy (w MariaDB/MySQL baza danych = schemat, w PostgreSQL schematy są wewnątrz bazy) pozwalają oddzielić dane i nadać różne uprawnienia. Przestrzenie tabel (tablespaces) pozwalają umieścić dane na wybranych dyskach, np. szybkim lub szyfrowanym.

Zmiany struktury bez zakłócania działania

  • wykonuj zmiany w oknie serwisowym, najpierw na kopii lub środowisku testowym,
  • przed zmianą wykonaj kopię zapasową,
  • dla dużych tabel używaj zmian online: ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE (MariaDB/MySQL), narzędzi do zmiany schematu bez blokad lub kolumn dodawanych jako opcjonalne,
  • pamiętaj, że w MariaDB/MySQL polecenia DDL zatwierdzają transakcję domyślnie, a w PostgreSQL DDL można wycofać w transakcji,
  • zmiany wprowadzaj skryptami i dokumentuj (lekcja 13).
Zmiana online (przykład)
ALTER TABLE oceny
  ADD COLUMN komentarz VARCHAR(200) NULL,
  ALGORITHM=INPLACE, LOCK=NONE;
Polecenia nieodwracalne

DROP i TRUNCATE usuwają dane bez możliwości wycofania (w większości SZBD). Przed wykonaniem upewnij się, na jakim serwerze i w jakiej bazie jesteś, i miej kopię.

Sprawdź się — zadanie 1

Czym różni się DELETE od TRUNCATE i DROP?

Pokaż przykładową odpowiedź

DELETE usuwa wskazane wiersze i można go wycofać w transakcji. TRUNCATE usuwa wszystkie wiersze tabeli (struktura zostaje), a DROP usuwa całą tabelę. TRUNCATE i DROP w wielu SZBD są nieodwracalne.

Sprawdź się — zadanie 2

Jak ograniczyć skutki zmiany struktury dużej tabeli na działającym systemie?

Pokaż przykładową odpowiedź

Zrobić kopię, przetestować zmianę na kopii, użyć mechanizmów zmiany online (np. ALGORITHM=INPLACE, LOCK=NONE) i wykonać zmianę w oknie serwisowym.

Lekcja 8 · Część B

Indeksy i widoki

Indeksy

Tworzenie i sprawdzanie
CREATE INDEX idx_oceny_uczen ON oceny (uczen_id);
CREATE INDEX idx_logowania_ip_czas ON logowania (adres_ip, czas);     -- indeks złożony
CREATE UNIQUE INDEX uq_uczniowie_email ON uczniowie (email);

EXPLAIN SELECT * FROM oceny WHERE uczen_id = 42;
SHOW INDEX FROM oceny;

W wyniku EXPLAIN kolumna type z wartością ALL oznacza pełne przeglądanie tabeli, a ref lub const użycie indeksu. W indeksie złożonym liczy się kolejność kolumn: indeks (adres_ip, czas) pomaga przy warunku na adres_ip, ale nie na samym czas.

  • indeks pomaga przy WHERE, JOIN, ORDER BY i GROUP BY,
  • nie pomaga przy kolumnach o małym zróżnicowaniu (np. płeć) ani przy funkcjach na kolumnie (WHERE YEAR(data) = 2026),
  • zbędne indeksy spowalniają zapis i zajmują miejsce.

Widoki

Widok jako ochrona danych
CREATE VIEW v_oceny_uczniow AS
SELECT u.imie, u.nazwisko, p.nazwa AS przedmiot, o.ocena
FROM oceny o
JOIN uczniowie u  ON u.id = o.uczen_id
JOIN przedmioty p ON p.id = o.przedmiot_id;

SELECT * FROM v_oceny_uczniow WHERE nazwisko = 'Kowalska';

Widok upraszcza złożone zapytania i pozwala udostępnić wybrane kolumny i wiersze bez dawania dostępu do tabel źródłowych. Zwykły widok nie przyspiesza zapytań, bo jest wykonywany przy każdym użyciu.

Sprawdź się — zadanie 1

Co oznacza wartość ALL w kolumnie type wyniku EXPLAIN?

Pokaż przykładową odpowiedź

Pełne przeglądanie tabeli (bez użycia indeksu). Przy dużych tabelach jest to wolne i zwykle sygnał, że warto dodać indeks.

Sprawdź się — zadanie 2

Do czego poza upraszczaniem zapytań służą widoki?

Pokaż przykładową odpowiedź

Do ograniczania dostępu do danych: widok ujawnia tylko wybrane kolumny i wiersze, więc użytkownik może dostać uprawnienie do widoku bez uprawnień do tabel.

Lekcja 9 · Część B

Klucze obce, kaskady i spójność referencyjna

Spójność referencyjna oznacza, że każdy klucz obcy wskazuje istniejący wiersz tabeli nadrzędnej. Baza nie pozwoli dodać ucznia z nieistniejącą klasą ani usunąć klasy, do której należą uczniowie (zależnie od ustawionej akcji).

Akcja przy usunięciu (ON DELETE)Działanie
RESTRICT / NO ACTIONblokuje usunięcie, gdy istnieją wiersze zależne (bezpieczne ustawienie domyślne)
CASCADEusuwa także wiersze zależne
SET NULLustawia klucz obcy na NULL (kolumna musi dopuszczać NULL)
SET DEFAULTustawia wartość domyślną (nie w InnoDB)
Klucz obcy z akcjami
ALTER TABLE oceny
  ADD CONSTRAINT fk_oceny_uczen
  FOREIGN KEY (uczen_id) REFERENCES uczniowie (id)
  ON DELETE CASCADE
  ON UPDATE RESTRICT;
Ostrożnie z CASCADE

ON DELETE CASCADE na kluczu prowadzącym do ważnych danych może jednym poleceniem usunąć setki powiązanych wierszy (klasa → uczniowie → oceny). Dla danych istotnych stosuj RESTRICT i usuwanie logiczne (lekcja 10).

Sprawdź się — zadanie 1

Co się stanie przy próbie usunięcia wiersza nadrzędnego, do którego odwołuje się klucz obcy z ON DELETE RESTRICT?

Pokaż przykładową odpowiedź

Baza odrzuci operację z błędem, dopóki istnieją wiersze zależne. Najpierw trzeba usunąć lub przenieść wiersze podrzędne.

Sprawdź się — zadanie 2

Dlaczego CASCADE bywa niebezpieczne?

Pokaż przykładową odpowiedź

Jedna operacja usunięcia może automatycznie usunąć wiele powiązanych danych, także tych, których użytkownik się nie spodziewał, co ułatwia przypadkową lub złośliwą utratę danych.

Lekcja 10 · Część B

Wstawianie, zmiana i usuwanie danych z rozliczalnością

DML: podstawy
INSERT INTO uczniowie (imie, nazwisko, email, klasa_id)
VALUES ('Anna', 'Kowalska', 'anna.k@szkola.pl', 3),
       ('Jan',  'Nowak',    'jan.n@szkola.pl',   3);

UPDATE uczniowie SET klasa_id = 4 WHERE id = 17;
DELETE FROM uczniowie WHERE id = 17;
Najpierw SELECT

Przed UPDATE i DELETE uruchom SELECT z tym samym warunkiem WHERE i sprawdź, które wiersze zostaną objęte. UPDATE lub DELETE bez WHERE zmienia lub usuwa wszystkie wiersze.

Rozliczalność i bezpieczne usuwanie

  • kolumny audytowe: utworzono, zmodyfikowano, zmodyfikowal (kto),
  • tabele historii lub wyzwalacze zapisujące poprzednie wartości (lekcja 27),
  • usuwanie logiczne: kolumna usunieto_at zamiast kasowania wiersza, a fizyczne usunięcie według procedury (po okresie retencji),
  • usuwanie zgodnie z procedurą: najpierw kopia/archiwum, potem usunięcie, potem weryfikacja, a także usunięcie z kopii zapasowych zgodnie z polityką,
  • nigdy nie wpisuj haseł w jawnej postaci do tabel i logów.
Kolumny audytowe i usuwanie logiczne
ALTER TABLE uczniowie
  ADD COLUMN zmodyfikowano DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
  ADD COLUMN usunieto_at   DATETIME NULL;

UPDATE uczniowie SET usunieto_at = NOW() WHERE id = 17;
SELECT * FROM uczniowie WHERE usunieto_at IS NULL;
Sprawdź się — zadanie 1

Co grozi po wykonaniu UPDATE uczniowie SET klasa_id = 1 bez klauzuli WHERE?

Pokaż przykładową odpowiedź

Wszyscy uczniowie zostaną przeniesieni do klasy 1. Dlatego przed zmianą sprawdza się warunek poleceniem SELECT i wykonuje zmianę w transakcji.

Sprawdź się — zadanie 2

Na czym polega usuwanie logiczne i jaka jest jego zaleta?

Pokaż przykładową odpowiedź

Wiersz nie jest kasowany, tylko oznaczany jako usunięty (np. kolumną z datą). Można go odtworzyć i zachować historię, a fizyczne usunięcie wykonuje się według procedury po okresie retencji.

Lekcja 11 · Część B

Transakcje w SQL: COMMIT, ROLLBACK i punkty przywracania

Masowa aktualizacja w transakcji
START TRANSACTION;

UPDATE oceny SET ocena = ocena + 0.5
WHERE przedmiot_id = 3 AND ocena < 5.5;

SELECT COUNT(*) AS zmienione FROM oceny WHERE przedmiot_id = 3 AND ocena > 5.5;   -- kontrola

COMMIT;       -- zatwierdź, jeśli wynik zgodny z oczekiwaniem
-- ROLLBACK;  -- albo wycofaj wszystkie zmiany
Punkty zachowania (SAVEPOINT)
START TRANSACTION;
INSERT INTO uczniowie (imie, nazwisko, email, klasa_id) VALUES ('A', 'B', 'a@b.pl', 3);
SAVEPOINT po_wstawieniu;
UPDATE uczniowie SET klasa_id = 99 WHERE email = 'a@b.pl';   -- błąd: nie ma klasy 99
ROLLBACK TO po_wstawieniu;      -- wycofuje tylko część zmian
COMMIT;
  • domyślnie wiele SZBD działa w trybie autocommit: każde polecenie jest zatwierdzane od razu; transakcję zaczynasz poleceniem START TRANSACTION,
  • COMMIT zatwierdza, ROLLBACK wycofuje, SAVEPOINT pozwala wycofać część zmian.

Poziomy izolacji

PoziomChroni przedUwagi
READ UNCOMMITTEDniczymmożliwy brudny odczyt
READ COMMITTEDbrudnym odczytemdomyślny w PostgreSQL
REPEATABLE READbrudnym i niepowtarzalnym odczytemdomyślny w InnoDB (MariaDB/MySQL)
SERIALIZABLEwszystkimi anomaliami (także fantomami)najwolniejszy

Przy dłuższych transakcjach rośnie ryzyko blokad i zakleszczeń (deadlock), więc transakcje powinny być krótkie.

Sprawdź się — zadanie 1

Co zrobisz, gdy po masowej aktualizacji w transakcji kontrola pokaże nieoczekiwany wynik?

Pokaż przykładową odpowiedź

Wykonam ROLLBACK, który wycofa wszystkie zmiany z transakcji, a następnie poprawię warunek i powtórzę operację.

Sprawdź się — zadanie 2

Do czego służy SAVEPOINT?

Pokaż przykładową odpowiedź

Pozwala wycofać tylko część zmian wykonanych w transakcji (do wskazanego punktu) bez wycofywania całej transakcji.

Lekcja 12 · Część B

Maskowanie danych wrażliwych i walidacja

Maskowanie ukrywa część danych wrażliwych przy ich wyświetlaniu, np. osobom z działu pomocy. Dane w tabeli pozostają kompletne, a użytkownik widzi wersję zasłoniętą.

Maskowanie w zapytaniu i w widoku
SELECT id,
       CONCAT(LEFT(email, 2), '***@', SUBSTRING_INDEX(email, '@', -1)) AS email_maska,
       CONCAT('*******', RIGHT(pesel, 4))                               AS pesel_maska
FROM dane;

CREATE VIEW v_wsparcie AS
SELECT id, imie, CONCAT(LEFT(email, 2), '***@', SUBSTRING_INDEX(email, '@', -1)) AS email
FROM uczniowie;
-- GRANT SELECT ON szkola.v_wsparcie TO rola_wsparcie;
Inne rozwiązania

Niektóre SZBD i bramy mają dynamiczne maskowanie (np. SQL Server, filtr maskowania w MariaDB MaxScale). Do środowisk testowych używa się anonimizacji: zamiany prawdziwych danych na fikcyjne, żeby nie kopiować danych osobowych poza produkcję.

Walidacja danych względem typów

  • włącz tryb ścisły (STRICT_TRANS_TABLES), aby błędne wartości kończyły się błędem,
  • używaj CHECK (np. ocena BETWEEN 1 AND 6), ENUM lub tabel słownikowych,
  • waliduj dane także w aplikacji: baza jest ostatnią linią obrony, nie jedyną (obrona warstwowa).
Sprawdź się — zadanie 1

Czym różni się maskowanie danych od szyfrowania?

Pokaż przykładową odpowiedź

Maskowanie zmienia sposób wyświetlania danych (ukrywa ich część), a dane w bazie pozostają jawne dla uprawnionych. Szyfrowanie zmienia zapisane dane tak, że bez klucza są nieczytelne.

Sprawdź się — zadanie 2

Dlaczego do testów nie powinno się używać kopii produkcyjnej danych osobowych?

Pokaż przykładową odpowiedź

Środowiska testowe są zwykle słabiej chronione, więc wzrasta ryzyko wycieku. Należy używać danych zanonimizowanych lub fikcyjnych.

Lekcja 13 · Część B

Dokumentowanie zmian i wersjonowanie schematu

Schemat bazy zmienia się razem z aplikacją. Zmiany wprowadzane ręcznie na serwerze są trudne do odtworzenia i śledzenia. Dlatego stosuje się migracje: kolejne, numerowane skrypty SQL przechowywane w repozytorium (np. Git).

Przykładowa struktura migracji
migracje/
  V001__utworz_tabele_podstawowe.sql
  V002__dodaj_kolumne_telefon.sql
  V003__indeks_oceny_uczen.sql
  V004__widok_wsparcie.sql
  • narzędzia takie jak Flyway i Liquibase zapamiętują w bazie, które migracje zostały wykonane (tabela historii),
  • każda migracja ma skrypt „w przód” i, jeśli to możliwe, skrypt cofający,
  • migracje przechodzą przegląd kodu i testy na kopii przed wdrożeniem,
  • obok skryptów utrzymuj dokumentację: aktualny diagram ERD i słownik danych (opis tabel i kolumn, typy, więzy, wrażliwość danych),
  • zmiany na produkcji wykonuj wyłącznie przez migracje, nigdy ręcznie.
Sprawdź się — zadanie 1

Dlaczego zmiany schematu bazy powinny być zapisywane jako migracje w repozytorium?

Pokaż przykładową odpowiedź

Pozwala to odtworzyć dowolny stan bazy, śledzić kto i kiedy zmienił schemat, przeglądać zmiany przed wdrożeniem i identycznie wdrażać je na wszystkich środowiskach.

Sprawdź się — zadanie 2

Co powinien zawierać słownik danych?

Pokaż przykładową odpowiedź

Opis tabel i kolumn: znaczenie, typ, więzy, wartości dozwolone, informację o wrażliwości danych oraz relacje między tabelami.

Zadanie praktyczne

Implementacja schematu, danych i bezpiecznych operacji

Szacowany czas: 60 minZakres: Lekcje 7–13Forma: skrypty SQL i krótka dokumentacja

Zadanie

Zaimplementuj schemat dziennika z zadania A i wykonaj bezpieczne operacje na danych.

Założenia

  • Utwórz bazę i tabele (z kluczami, więzami i indeksami), oddzielając dane wrażliwe. Każdą zmianę zapisz jako osobną migrację (plik V001__...sql).
  • Dodaj widok ukrywający dane wrażliwe i widok maskujący adres e-mail dla roli wsparcia.
  • Wstaw przykładowe dane. Wykonaj masową aktualizację ocen w transakcji z kontrolą wyniku, a potem wycofaj ją poleceniem ROLLBACK i zweryfikuj powrót danych.
  • Zademonstruj działanie klucza obcego (próba wstawienia ucznia z nieistniejącą klasą) i wpływ ON DELETE RESTRICT na usuwanie klasy.
  • Dodaj kolumny audytowe i usuwanie logiczne. Opisz w 3–4 zdaniach, jak procedura usuwania chroni dane.

Ocenie podlegać będzie

  • poprawna struktura i migracje,
  • poprawne widoki i maskowanie,
  • poprawne użycie transakcji,
  • zrozumienie więzów i akcji referencyjnych,
  • czytelna dokumentacja.
Wskazówki
  • Każdą migrację testuj na pustej bazie testowej.
  • Przed UPDATE sprawdź warunek poleceniem SELECT.
  • Skorzystaj z przykładów w lekcjach 7–13.

Część C

Zapytania SQL i analiza danych

SELECT, JOIN, agregacje, podzapytania, wykrywanie anomalii i ataków w logach oraz weryfikacja zapytań tworzonych z pomocą AI.

Lekcja 14 · Część C

SELECT: wybieranie, filtrowanie i sortowanie danych

W tej części korzystamy z przykładowych tabel: uzytkownicy(id, login, rola) i logowania(id, uzytkownik_id, adres_ip, wynik, czas), gdzie wynik to „OK” lub „BLAD”.

Podstawowe zapytania
SELECT login, rola FROM uzytkownicy WHERE rola IN ('admin', 'kadry') ORDER BY login;

SELECT DISTINCT adres_ip FROM logowania WHERE wynik = 'BLAD';

SELECT id, czas FROM logowania
WHERE czas BETWEEN '2026-10-05 00:00:00' AND '2026-10-05 23:59:59'
ORDER BY czas DESC
LIMIT 20;

SELECT login FROM uzytkownicy WHERE login LIKE 'a%';       -- zaczyna się od „a”
SELECT login FROM uzytkownicy WHERE telefon IS NULL;       -- uwaga: nie „= NULL”
KlauzulaZadanie
SELECTktóre kolumny lub wyrażenia zwrócić (unikaj SELECT * w kodzie aplikacji)
FROMz jakiej tabeli lub widoku
WHEREfiltruje wiersze przed grupowaniem
GROUP BY, HAVINGgrupowanie i filtrowanie grup
ORDER BYsortowanie wyniku
LIMITograniczenie liczby wierszy
NULL

NULL oznacza „brak wartości”. Porównanie kolumna = NULL nigdy nie daje prawdy. Używaj IS NULL i IS NOT NULL. Wyrażenia z NULL zwykle dają NULL (np. 5 + NULL).

Sprawdź się — zadanie 1

Czym różni się WHERE od HAVING?

Pokaż przykładową odpowiedź

WHERE filtruje pojedyncze wiersze przed grupowaniem, a HAVING filtruje grupy po zastosowaniu funkcji agregujących (np. COUNT).

Sprawdź się — zadanie 2

Dlaczego zapytanie SELECT * FROM t WHERE telefon = NULL nie zwróci wierszy z pustym telefonem?

Pokaż przykładową odpowiedź

Porównanie z NULL nigdy nie daje prawdy. Poprawny zapis to WHERE telefon IS NULL.

Lekcja 15 · Część C

JOIN: łączenie tabel i korelowanie logów

Dane z kilku tabel łączy się klauzulą JOIN na podstawie kluczy. To podstawowe narzędzie analizy zdarzeń: np. powiązanie logów logowania z kontami użytkowników.

JOINWynik
INNER JOIN (JOIN)tylko wiersze mające pary w obu tabelach
LEFT JOINwszystkie wiersze lewej tabeli; brakujące dane z prawej jako NULL
RIGHT JOINwszystkie wiersze prawej tabeli
FULL OUTER JOINwiersze z obu tabel (PostgreSQL; w MySQL/MariaDB przez UNION)
CROSS JOINiloczyn kartezjański: każdy z każdym
Nieudane logowania w ostatniej godzinie z nazwą użytkownika
SELECT u.login, l.adres_ip, l.czas
FROM logowania l
JOIN uzytkownicy u ON u.id = l.uzytkownik_id
WHERE l.wynik = 'BLAD'
  AND l.czas >= NOW() - INTERVAL 1 HOUR
ORDER BY l.czas DESC;
LEFT JOIN: konta, które nigdy się nie zalogowały
SELECT u.login
FROM uzytkownicy u
LEFT JOIN logowania l ON l.uzytkownik_id = u.id
WHERE l.id IS NULL;
Korelowanie wielu źródeł

Łącząc tabele logów (logowania, zdarzenia systemowe, zmiany uprawnień) po wspólnych kluczach lub czasie, odtwarzasz przebieg incydentu: kto, skąd, kiedy i co potem zrobił.

Sprawdź się — zadanie 1

Czym różni się INNER JOIN od LEFT JOIN?

Pokaż przykładową odpowiedź

INNER JOIN zwraca tylko wiersze, które mają odpowiednik w obu tabelach. LEFT JOIN zwraca wszystkie wiersze lewej tabeli, a brakujące dane z prawej uzupełnia wartościami NULL.

Sprawdź się — zadanie 2

Jak znajdziesz konta bez żadnego logowania?

Pokaż przykładową odpowiedź

LEFT JOIN tabeli kont z logowaniami i warunek WHERE l.id IS NULL, który zostawia konta bez odpowiadających wierszy w tabeli logowań.

Lekcja 16 · Część C

Funkcje agregujące, GROUP BY i wykrywanie ataków brute-force

Funkcje agregujące zwracają jedną wartość dla grupy wierszy: COUNT, SUM, AVG, MIN, MAX. Z GROUP BY liczą wartości osobno dla każdej grupy.

Adresy z wieloma nieudanymi logowaniami w ostatnich 15 minutach
SELECT adres_ip,
       COUNT(*)  AS proby,
       MIN(czas) AS pierwsza,
       MAX(czas) AS ostatnia
FROM logowania
WHERE wynik = 'BLAD'
  AND czas >= NOW() - INTERVAL 15 MINUTE
GROUP BY adres_ip
HAVING COUNT(*) >= 10
ORDER BY proby DESC;

Wiele błędnych prób z jednego adresu w krótkim czasie to typowy sygnał ataku brute-force. Podobnie wykrywa się anomalie statystyczne: konta z liczbą logowań wyraźnie powyżej średniej lub aktywność w nietypowych godzinach.

Konta z nietypową liczbą logowań (powyżej średniej + 3 odchylenia)
SELECT uzytkownik_id, COUNT(*) AS liczba
FROM logowania
WHERE czas >= NOW() - INTERVAL 1 DAY
GROUP BY uzytkownik_id
HAVING COUNT(*) > (SELECT AVG(c) + 3 * STDDEV(c)
                   FROM (SELECT COUNT(*) AS c FROM logowania
                         WHERE czas >= NOW() - INTERVAL 1 DAY
                         GROUP BY uzytkownik_id) t);
Zasada GROUP BY

Każda kolumna w SELECT, która nie jest funkcją agregującą, musi występować w GROUP BY. W przeciwnym razie wynik jest niejednoznaczny (i część SZBD zgłosi błąd).

Sprawdź się — zadanie 1

Co robi klauzula HAVING COUNT(*) >= 10 w zapytaniu z GROUP BY adres_ip?

Pokaż przykładową odpowiedź

Zostawia tylko te adresy IP, dla których w grupie jest co najmniej 10 wierszy (np. 10 nieudanych logowań).

Sprawdź się — zadanie 2

Jak za pomocą SQL wykryjesz prawdopodobny atak brute-force na logowanie?

Pokaż przykładową odpowiedź

Zliczam nieudane logowania pogrupowane po adresie IP (lub koncie) w krótkim oknie czasowym i wybieram grupy z liczbą prób powyżej progu (GROUP BY + HAVING).

Lekcja 17 · Część C

Podzapytania i wykrywanie nieautoryzowanych powiązań

Podzapytanie to zapytanie zagnieżdżone w innym. Może zwracać jedną wartość, listę wartości lub tabelę pomocniczą. Skorelowane podzapytanie odwołuje się do wiersza zapytania zewnętrznego.

Rodzaje podzapytań
-- skalarne: konta z największą liczbą logowań
SELECT login FROM uzytkownicy
WHERE id = (SELECT uzytkownik_id FROM logowania GROUP BY uzytkownik_id ORDER BY COUNT(*) DESC LIMIT 1);

-- IN: użytkownicy z nieudanymi logowaniami
SELECT login FROM uzytkownicy
WHERE id IN (SELECT uzytkownik_id FROM logowania WHERE wynik = 'BLAD');

-- tabela pochodna w FROM
SELECT AVG(liczba) FROM (SELECT COUNT(*) AS liczba FROM logowania GROUP BY adres_ip) t;

Podzapytania świetnie nadają się do znajdowania nieautoryzowanych powiązań, np. użytkowników, którzy mają dostęp do zasobu, choć nie mają wymaganej roli:

Dostęp do danych płacowych bez roli „kadry”
SELECT d.uzytkownik_id
FROM dostepy d
WHERE d.zasob = 'place'
  AND NOT EXISTS (SELECT 1
                  FROM role_uzytkownikow r
                  WHERE r.uzytkownik_id = d.uzytkownik_id
                    AND r.rola = 'kadry');
CTE

Wyrażenia WITH nazwa AS (...) (CTE) czynią złożone zapytania czytelniejszymi. Są dostępne w MariaDB 10.2+, MySQL 8 i PostgreSQL.

Sprawdź się — zadanie 1

Do czego służy EXISTS w podzapytaniu?

Pokaż przykładową odpowiedź

Sprawdza, czy podzapytanie zwraca jakikolwiek wiersz. Z NOT EXISTS znajduje wiersze, dla których nie istnieje powiązany wiersz.

Sprawdź się — zadanie 2

Jak znajdziesz użytkowników mających uprawnienie do zasobu, ale bez wymaganej roli?

Pokaż przykładową odpowiedź

Zapytaniem z NOT EXISTS (lub NOT IN), które dla każdego wpisu dostępu sprawdza brak odpowiedniej roli w tabeli ról.

Lekcja 18 · Część C

Generatywna AI i zapytania SQL: tworzenie, refaktoryzacja i weryfikacja

Narzędzia generatywnej AI potrafią napisać zapytanie SQL na podstawie opisu w języku naturalnym, zaproponować czytelniejszą wersję i wyjaśnić działanie istniejącego kodu. Wynik zawsze wymaga weryfikacji: zapytanie może wyglądać poprawnie, a zwracać błędne dane.

Dobry opis zadania dla AI

  • podaj schemat (nazwy tabel, kolumn, typy, klucze), bez prawdziwych danych,
  • określ dialekt SQL (MariaDB, PostgreSQL),
  • opisz oczekiwany wynik i warunki (zakres czasu, progi),
  • poproś o wyjaśnienie kroków, aby łatwiej sprawdzić poprawność.

Weryfikacja ręczna

KontrolaJak
Czy kolumny i tabele istniejąuruchom na testowej bazie; AI bywa „halucynować” nazwy
Czy JOIN nie mnoży wierszyporównaj liczbę wierszy z oczekiwaną; sprawdź klucze łączenia
Czy wynik jest poprawnyprzetestuj na małym zbiorze z znanym wynikiem
WydajnośćEXPLAIN, zwróć uwagę na pełne przeglądanie tabel
Bezpieczeństwoszukaj DELETE/UPDATE bez WHERE, DROP, zmian uprawnień
Przykład: polecenie z AI, które trzeba odrzucić lub poprawić
-- „Usuń nieaktywnych użytkowników”
DELETE FROM uzytkownicy;                      -- brak WHERE: usunie wszystkich!

-- Poprawnie (po kontroli SELECT i w transakcji):
START TRANSACTION;
SELECT COUNT(*) FROM uzytkownicy WHERE ostatnie_logowanie < NOW() - INTERVAL 2 YEAR;
UPDATE uzytkownicy SET usunieto_at = NOW() WHERE ostatnie_logowanie < NOW() - INTERVAL 2 YEAR;
COMMIT;
Ryzyka

Nie wklejaj do narzędzi AI danych osobowych, haseł ani zrzutów prawdziwych baz. Kod SQL tworzony w aplikacji z użyciem konkatenacji tekstów (zamiast zapytań parametryzowanych) jest podatny na SQL Injection także wtedy, gdy wygenerowała go AI.

Sprawdź się — zadanie 1

Jakich informacji nie wolno przekazywać narzędziu AI przy pisaniu zapytań?

Pokaż przykładową odpowiedź

Prawdziwych danych osobowych, haseł, kluczy i zawartości produkcyjnych baz. Wystarczy sam schemat (nazwy i typy) oraz opis zadania.

Sprawdź się — zadanie 2

Jak sprawdzisz zapytanie SQL wygenerowane przez AI przed użyciem w systemie?

Pokaż przykładową odpowiedź

Uruchomię je na testowej kopii z małym zbiorem o znanym wyniku, sprawdzę liczbę i treść wierszy, plan wykonania (EXPLAIN) oraz brak niebezpiecznych poleceń (DELETE/UPDATE bez WHERE, DROP).

Zadanie praktyczne

Analiza logów logowania w bazie danych

Szacowany czas: 60 minZakres: Lekcje 14–18Forma: zestaw zapytań i wnioski

Zadanie

Dostajesz tabele uzytkownicy(id, login, rola), logowania(id, uzytkownik_id, adres_ip, wynik, czas) i dostepy(uzytkownik_id, zasob). Utwórz je w bazie testowej, wstaw kilkadziesiąt przykładowych wierszy (w tym symulowany atak) i napisz zapytania.

Założenia

  • Wypisz nieudane logowania z ostatnich 24 godzin wraz z loginem użytkownika (JOIN).
  • Znajdź adresy IP z co najmniej 10 nieudanymi próbami w 15 minut (GROUP BY + HAVING).
  • Znajdź konta, które zalogowały się poprawnie zaraz po serii błędnych prób z tego samego adresu IP.
  • Znajdź użytkowników z dostępem do zasobu „place” bez roli „kadry” (NOT EXISTS).
  • Poproś narzędzie AI o jedno z zapytań, zweryfikuj je (test na znanych danych, EXPLAIN) i opisz znalezione błędy lub potwierdź poprawność.

Ocenie podlegać będzie

  • poprawność zapytań i wyników,
  • umiejętność wykrycia wzorca ataku,
  • poprawne użycie JOIN, agregacji i podzapytań,
  • krytyczna weryfikacja kodu z AI,
  • czytelność i opis wniosków.
Wskazówki
  • Dla zapytania 3 użyj samozłączenia lub podzapytania po adresie IP i czasie.
  • Dodaj indeks na (adres_ip, czas) i sprawdź EXPLAIN.
  • Skorzystaj z przykładów w lekcjach 15–17.

Część D

Administracja SZBD, kopie zapasowe i odtwarzanie

Instalacja i konfiguracja serwera, dostęp lokalny i zdalny, wydajność i miejsce, kopie zapasowe, odtwarzanie, harmonogram i logi.

Lekcja 19 · Część D

Instalacja i konfiguracja serwera bazy danych

Po instalacji SZBD (np. apt install mariadb-server w Linux, instalator MSI lub pakiet WAMP w Windows) wykonuje się wstępne zabezpieczenie i konfigurację.

Wstępne zabezpieczenie (MariaDB)
sudo mariadb-secure-installation
# ustaw hasło/uwierzytelnianie root, usuń anonimowych użytkowników,
# zablokuj zdalne logowanie roota, usuń bazę „test”, przeładuj uprawnienia
Fragment konfiguracji (/etc/mysql/mariadb.conf.d/50-server.cnf lub my.ini)
[mysqld]
bind-address = 127.0.0.1        # nasłuch tylko lokalnie
port         = 3306
sql_mode     = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
local_infile = 0
DostępKonfiguracjaUwagi
Lokalnygniazdo Unix lub 127.0.0.1najbezpieczniejszy; konto root może używać uwierzytelniania gniazdem (unix_socket)
Zdalnybind-address na wybrany interfejs, konto 'u'@'adres', otwarty port w zaporzeogranicz do sieci aplikacji, wymuś TLS, nie wystawiaj portu 3306 do internetu
Konto dla zdalnej aplikacji z jednej podsieci
CREATE USER 'app'@'10.0.20.%' IDENTIFIED BY 'LosoweDlugieHaslo!';
GRANT SELECT, INSERT, UPDATE ON szkola.* TO 'app'@'10.0.20.%';
PostgreSQL

W PostgreSQL nasłuch ustawia listen_addresses w postgresql.conf, a dostęp zdalny określa pg_hba.conf (kto, do jakiej bazy, z jakiego adresu i jaką metodą uwierzytelnienia).

Sprawdź się — zadanie 1

Dlaczego po instalacji uruchamia się mariadb-secure-installation?

Pokaż przykładową odpowiedź

Usuwa niebezpieczne ustawienia domyślne: anonimowych użytkowników, zdalne logowanie roota i bazę testową oraz pozwala ustawić silne uwierzytelnianie konta administratora.

Sprawdź się — zadanie 2

Co oznacza bind-address = 127.0.0.1?

Pokaż przykładową odpowiedź

Serwer nasłuchuje tylko na pętli zwrotnej, więc połączenia są możliwe wyłącznie z tego samego komputera. Zdalny dostęp wymaga zmiany ustawienia i zabezpieczenia (zapora, TLS, ograniczenie kont).

Lekcja 20 · Część D

Przestrzeń dyskowa, wydajność i monitorowanie serwera

Rozmiary baz i tabel
SELECT table_schema AS baza,
       ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) AS rozmiar_mb
FROM information_schema.tables
GROUP BY table_schema
ORDER BY rozmiar_mb DESC;
Stan serwera i wolne zapytania
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW FULL PROCESSLIST;                       -- aktualnie wykonywane zapytania
SHOW GLOBAL VARIABLES LIKE 'slow_query_log%';

-- w konfiguracji: logowanie wolnych zapytań
slow_query_log      = 1
long_query_time     = 1
log_queries_not_using_indexes = 1
ZagadnienieCo robić
Miejsce na dyskumonitoruj zajętość (df -h), rotuj logi binarne i błędów, osobna partycja na dane
Wydajność zapytańEXPLAIN, indeksy, log wolnych zapytań, optymalizacja kodu
Pamięćustaw rozmiar bufora (np. innodb_buffer_pool_size) odpowiednio do zasobów
Połączenialimit max_connections, pula połączeń w aplikacji
Statystyki i tabeleANALYZE TABLE (statystyki), OPTIMIZE TABLE (defragmentacja)
Dostępność

Zapełnienie dysku (np. przez rosnące logi binarne) powoduje zatrzymanie bazy. To także wektor ataku typu DoS, więc monitoruj miejsce i ustaw automatyczne wygasanie logów (binlog_expire_logs_seconds).

Sprawdź się — zadanie 1

Jak sprawdzisz, jakie zapytania serwer wykonuje w tej chwili?

Pokaż przykładową odpowiedź

Poleceniem SHOW FULL PROCESSLIST (lub widokiem information_schema.PROCESSLIST).

Sprawdź się — zadanie 2

Do czego służy log wolnych zapytań?

Pokaż przykładową odpowiedź

Zapisuje zapytania wykonujące się dłużej niż ustalony próg, co pozwala znaleźć miejsca wymagające indeksu lub optymalizacji.

Lekcja 21 · Część D

Kopie zapasowe baz danych

RodzajOpisNarzędziaZalety i wady
Logicznazapis poleceń SQL odtwarzających danemariadb-dump (mysqldump), pg_dumpprzenośna, łatwa do analizy; wolna dla dużych baz
Fizycznakopia plików danychmariabackup, pg_basebackupszybka dla dużych baz; związana z wersją i systemem
Przyrostowatylko zmiany od poprzedniej kopiimariabackup --incremental-basedir, archiwizacja WAL/binlogoszczędza miejsce; odtwarzanie wymaga łańcucha
Kopia logiczna
mariadb-dump --single-transaction --routines --triggers --events \
             --databases szkola > szkola_$(date +%F).sql

pg_dump -Fc szkola > szkola_$(date +%F).dump        # PostgreSQL
Kopia fizyczna pełna i przyrostowa (MariaDB)
mariabackup --backup --target-dir=/kopie/pelna --user=kopie --password='...'
mariabackup --backup --target-dir=/kopie/inc1 --incremental-basedir=/kopie/pelna --user=kopie --password='...'
mariabackup --prepare --target-dir=/kopie/pelna
  • --single-transaction daje spójną kopię tabel InnoDB bez blokowania zapisu,
  • dziennik binarny (binlog) i WAL (PostgreSQL) pozwalają odtworzyć stan z konkretnej chwili (PITR),
  • kopie szyfruj i chroń uprawnieniami (chmod 600), a hasło do kopii trzymaj w magazynie sekretów,
  • kopie przechowuj zgodnie z zasadą 3-2-1 i testuj odtwarzanie.
Sprawdź się — zadanie 1

Czym różni się kopia logiczna od fizycznej?

Pokaż przykładową odpowiedź

Kopia logiczna zapisuje polecenia SQL (dane i struktury) i jest przenośna, ale wolniejsza. Fizyczna kopiuje pliki danych serwera, jest szybka dla dużych baz, ale zależy od wersji i konfiguracji serwera.

Sprawdź się — zadanie 2

Po co stosuje się opcję --single-transaction w mysqldump?

Pokaż przykładową odpowiedź

Aby uzyskać spójną kopię tabel transakcyjnych (InnoDB) w jednej chwili bez blokowania zapisu przez całą kopię.

Lekcja 22 · Część D

Odtwarzanie po awarii, harmonogram i monitorowanie logów

Odtwarzanie

Odtworzenie z kopii logicznej i do wskazanego momentu
# odtworzenie bazy z kopii
mariadb < szkola_2026-10-05.sql

# odtworzenie do chwili sprzed błędnego polecenia (PITR): kopia pełna + dziennik binarny
mariadb-binlog --start-datetime="2026-10-05 10:00:00" --stop-datetime="2026-10-05 10:29:59" \
               /var/lib/mysql/mariadb-bin.000012 | mariadb

Procedura: zatrzymaj aplikację (lub przełącz w tryb tylko do odczytu), odtwórz dane na osobnej instancji, sprawdź spójność (liczby rekordów, wybrane zapytania, CHECK TABLE), a dopiero potem przywróć ruch. Odtwarzanie ćwicz regularnie, bo nieprzetestowana kopia nie jest gwarancją.

Harmonogram zadań

Kopia nocna i czyszczenie starych plików (cron)
# crontab -e (konto kopii)
30 1 * * *  /usr/local/bin/kopia_baz.sh
0  4 * * 0  find /kopie -name "*.sql.gz" -mtime +30 -delete

Logi i wykrywanie błędów oraz prób nadużyć

  • dziennik błędów (np. /var/log/mysql/error.log) pokazuje awarie, błędy uruchamiania, zapełnienie dysku,
  • komunikat Access denied for user powtarzany z jednego adresu to sygnał próby zgadywania hasła,
  • regularnie rotuj i czyść logi, ale archiwizuj te potrzebne do audytu,
  • wysyłaj logi do centralnego systemu (SIEM) i ustaw alerty na krytyczne błędy.

Zasada 3-2-1: trzy kopie danych, na dwóch różnych nośnikach, jedna poza lokalizacją podstawową (lub niezmienialna kopia odłączona od sieci, ochrona przed ransomware).

Sprawdź się — zadanie 1

Co umożliwia dziennik binarny w odtwarzaniu bazy?

Pokaż przykładową odpowiedź

Odtworzenie stanu z konkretnej chwili (PITR): po przywróceniu kopii pełnej odtwarza się zapisane w dzienniku zmiany do wybranego momentu, np. tuż przed błędnym usunięciem danych.

Sprawdź się — zadanie 2

Jak rozpoznasz w logach próbę zgadywania hasła do bazy?

Pokaż przykładową odpowiedź

Wiele komunikatów Access denied for user w krótkim czasie dla tego samego konta lub z jednego adresu IP. Warto ustawić na to alert.

Zadanie praktyczne

Plan administracyjny serwera bazy danych

Szacowany czas: 75 minZakres: Lekcje 19–22Forma: konfiguracja, skrypty i dokument planu

Zadanie

Zainstaluj serwer bazy danych na maszynie testowej i przygotuj plan jego utrzymania.

Założenia

  • Zainstaluj SZBD, uruchom skrypt zabezpieczający, ustaw nasłuch lokalny i tryb ścisły. Opisz, jak umożliwisz zdalny dostęp aplikacji z jednej podsieci (konto, zapora, TLS).
  • Napisz zapytanie pokazujące rozmiary baz i włącz log wolnych zapytań. Opisz, kiedy dodasz indeks.
  • Przygotuj skrypt kopii nocnej (kopia logiczna), zaplanuj go w cron i opisz retencję oraz miejsca przechowywania zgodnie z 3-2-1.
  • Wykonaj symulowaną awarię (usuń dane z tabeli testowej) i odtwórz je z kopii. Zapisz czas odtworzenia i porównaj dane.
  • Zaproponuj trzy alerty na podstawie logów i miejsc na dysku (np. brak miejsca, błędy logowania, awaria kopii).

Ocenie podlegać będzie

  • poprawna instalacja i zabezpieczenie,
  • poprawny skrypt i harmonogram kopii,
  • udane i udokumentowane odtworzenie,
  • sensowny plan monitorowania,
  • zgodność z zasadą 3-2-1.
Wskazówki
  • Polecenia znajdziesz w lekcjach 19–22.
  • Odtwarzanie ćwicz na osobnej instancji lub testowej bazie.
  • Hasła do kopii trzymaj poza skryptem.

Część E

Bezpieczeństwo baz danych: dostęp, szyfrowanie, audyt

Konta i role, hasła i sekrety, integracja z katalogiem, szyfrowanie, audyt i wyzwalacze, monitorowanie oraz utwardzanie serwera.

Lekcja 23 · Część E

Użytkownicy, role i zasada najmniejszych uprawnień

Dostęp do bazy nadaje się przez konta i role. Zasada najmniejszych uprawnień oznacza, że każde konto ma tylko takie prawa, jakich wymaga jego zadanie, i nic więcej.

Konta, uprawnienia i role (MariaDB)
CREATE USER 'raport'@'10.0.20.%' IDENTIFIED BY '...';
GRANT SELECT ON szkola.v_oceny_uczniow TO 'raport'@'10.0.20.%';        -- tylko widok, tylko odczyt

CREATE ROLE nauczyciel;
GRANT SELECT, INSERT, UPDATE ON szkola.oceny TO nauczyciel;
GRANT SELECT ON szkola.uczniowie TO nauczyciel;
GRANT nauczyciel TO 'anna'@'%';
SET DEFAULT ROLE nauczyciel FOR 'anna'@'%';

SHOW GRANTS FOR 'anna'@'%';
REVOKE INSERT ON szkola.oceny FROM nauczyciel;
DROP USER 'anna'@'%';                                                     -- po odejściu pracownika
Typ kontaUprawnieniaUwagi
AplikacyjneSELECT, INSERT, UPDATE (czasem DELETE) do swoich tabelbez DROP, ALTER, FILE
Raportowetylko SELECT na widokiosobne konto, najlepiej na replice
MigracyjneCREATE, ALTER w swoim schemacieużywane tylko podczas wdrożeń
Administracyjneszerokieimienne konta administratorów, MFA do dostępu do serwera, ograniczony zakres adresów
Czego unikać

GRANT ALL PRIVILEGES ON *.*, uprawnień GRANT OPTION, FILE, SUPER dla kont aplikacji oraz wspólnych kont używanych przez wiele osób (brak rozliczalności). Okresowo przeglądaj nadane prawa i usuwaj zbędne.

Sprawdź się — zadanie 1

Jakich uprawnień potrzebuje konto aplikacji WWW, która tylko odczytuje i dopisuje dane w swoich tabelach?

Pokaż przykładową odpowiedź

SELECT i INSERT (ewentualnie UPDATE) na tych tabelach. Nie powinno mieć DROP, ALTER, FILE ani praw administratora.

Sprawdź się — zadanie 2

Jaką korzyść daje użycie ról zamiast nadawania uprawnień każdemu użytkownikowi osobno?

Pokaż przykładową odpowiedź

Uprawnienia definiuje się raz dla roli, a użytkownika dodaje się do roli. Ułatwia to zarządzanie, spójność i audyt oraz szybkie odebranie dostępu.

Lekcja 24 · Część E

Hasła, MFA i magazyny sekretów

Polityka haseł i rotacja

  • silne, długie i losowe hasła dla kont serwisowych, zapisane w magazynie sekretów (nie w kodzie),
  • polityka haseł: plugin sprawdzający jakość hasła (np. simple_password_check w MariaDB, validate_password w MySQL),
  • rotacja haseł kont serwisowych według harmonogramu, najlepiej automatyczna,
  • wygasanie haseł kont ludzkich tylko tam, gdzie wymaga tego polityka (zgodnie z aktualnymi zaleceniami nie wymusza się zbyt częstych zmian).
Wygasanie hasła i blokada konta
ALTER USER 'serwis'@'10.0.20.5' PASSWORD EXPIRE INTERVAL 90 DAY;
ALTER USER 'anna'@'%' ACCOUNT LOCK;        -- czasowa blokada konta

Sekrety dla aplikacji

Aplikacja potrzebuje hasła do bazy, ale nie powinno ono leżeć w kodzie ani w repozytorium. Dobre sposoby dostarczania sekretów:

SposóbOpis
Magazyn sekretówzewnętrzna usługa (np. HashiCorp Vault, menedżer sekretów dostawcy chmury); aplikacja pobiera hasło po uwierzytelnieniu, a sekret można rotować
Zmienne środowiskowewstrzykiwane przy uruchomieniu; nie trafiają do repozytorium
Plik konfiguracyjny poza repozytoriumz prawem odczytu tylko dla konta aplikacji (chmod 600)

Uwierzytelnianie wieloskładnikowe dla administratorów

Większość SZBD nie ma wbudowanego MFA dla zwykłych połączeń, dlatego stosuje się je na poziomie dostępu do serwera: administrator łączy się przez VPN lub bastion z MFA (TOTP, klucz FIDO2/U2F), a konta administracyjne można uwierzytelniać przez PAM lub SSO. Dostęp bezpośredni z internetu do portu bazy jest wykluczony.

Sprawdź się — zadanie 1

Dlaczego hasło do bazy nie powinno być zapisane w pliku kodu aplikacji?

Pokaż przykładową odpowiedź

Kod trafia do repozytoriów i kopii, a wyciek pliku ujawnia hasło. Sekrety trzyma się w magazynie sekretów lub w konfiguracji poza repozytorium z ograniczonymi uprawnieniami.

Sprawdź się — zadanie 2

Jak zapewnić MFA administratorom bazy, jeśli SZBD go nie obsługuje?

Pokaż przykładową odpowiedź

Wymagać połączenia przez VPN lub bastion z uwierzytelnianiem wieloskładnikowym i ograniczyć dostęp do portu bazy do tej sieci, a konta administracyjne uwierzytelniać przez PAM lub SSO.

Lekcja 25 · Część E

Integracja z LDAP/Active Directory, limity i okna czasowe

Centralne zarządzanie tożsamością (LDAP, Active Directory) pozwala zarządzać kontami w jednym miejscu: wyłączenie konta w AD blokuje dostęp do bazy, a zmiany grup przekładają się na uprawnienia.

SZBDSposób integracji
MariaDB / MySQLwtyczka PAM (IDENTIFIED VIA pam) przekazująca uwierzytelnianie do SSSD/LDAP/AD
PostgreSQLmetoda ldap lub gss (Kerberos) w pg_hba.conf
SQL Serveruwierzytelnianie zintegrowane z Windows (Active Directory)
PostgreSQL: wpis w pg_hba.conf dla użytkowników z LDAP
# TYPE  DATABASE  USER  ADDRESS         METHOD
host    szkola    all   10.0.20.0/24    ldap ldapserver=ldap.szkola.local ldapprefix="uid=" ldapsuffix=",ou=ludzie,dc=szkola,dc=local" ldaptls=1

Limity sesji i konta techniczne

Limity zasobów dla konta (MariaDB/MySQL)
CREATE USER 'raport'@'10.0.20.%' IDENTIFIED BY '...'
  WITH MAX_USER_CONNECTIONS 5 MAX_QUERIES_PER_HOUR 5000;

SET GLOBAL wait_timeout = 600;           -- zamykanie bezczynnych sesji po 10 minutach
  • limity (liczba połączeń, zapytań na godzinę, czas bezczynności) ograniczają skutki przejęcia konta i nadużyć,
  • okna czasowe (dostęp tylko w godzinach pracy dla kont technicznych) realizuje się zwykle poza SZBD: modułem PAM (pam_time), regułami zapory lub zdarzeniami, które blokują i odblokowują konto,
  • konta techniczne (kopie, raporty) powinny być osobne, z minimalnymi prawami i ograniczonym adresem.
Sprawdź się — zadanie 1

Jaką korzyść daje integracja bazy z Active Directory?

Pokaż przykładową odpowiedź

Centralne zarządzanie kontami: wyłączenie konta w AD odcina dostęp do bazy, a grupy w AD mogą wyznaczać role. Zmniejsza się liczba osobnych haseł i błędów administracyjnych.

Sprawdź się — zadanie 2

Po co ustawia się limity połączeń i zapytań dla kont raportowych?

Pokaż przykładową odpowiedź

Aby ograniczyć skutki nadużycia lub przejęcia konta (np. masowy eksport danych, przeciążenie serwera) oraz zapobiec zajmowaniu wszystkich połączeń przez jedno konto.

Lekcja 26 · Część E

Szyfrowanie: w spoczynku i w ruchu

RodzajChroni przedSposoby
W spoczynku (at rest)odczytem danych z dysku lub kopii po kradzieży nośnikaszyfrowanie tabel i dzienników przez SZBD (TDE), szyfrowanie dysku (LUKS, BitLocker), szyfrowanie kopii
W ruchu (in transit)podsłuchem i zmianą danych w sieciTLS 1.2/1.3 między klientem a serwerem, wymuszenie szyfrowanych połączeń
Na poziomie aplikacji / kolumndostępem administratorów bazy do konkretnych danychszyfrowanie wartości w aplikacji (AES-GCM), klucze w magazynie kluczy (KMS)
MariaDB: szyfrowanie InnoDB i wymuszenie TLS
# konfiguracja
[mysqld]
plugin_load_add = file_key_management
file_key_management_filename = /etc/mysql/encryption/keyfile.enc
innodb_encrypt_tables = ON
innodb_encrypt_log    = ON
ssl_ca   = /etc/mysql/tls/ca.pem
ssl_cert = /etc/mysql/tls/server-cert.pem
ssl_key  = /etc/mysql/tls/server-key.pem
tls_version = TLSv1.2,TLSv1.3
Konto wymagające szyfrowanego połączenia
ALTER USER 'app'@'10.0.20.%' REQUIRE SSL;
SHOW STATUS LIKE 'Ssl_cipher';            -- w sesji klienta: czy połączenie jest szyfrowane
Klucze

Szyfrowanie jest tak mocne, jak ochrona kluczy. Klucze trzymaj osobno od danych (KMS, moduł HSM), rotuj je i kontroluj dostęp. Szyfrowanie dysku nie chroni przed użytkownikiem, który ma dostęp do działającej bazy.

Sprawdź się — zadanie 1

Przed czym chroni szyfrowanie danych w spoczynku?

Pokaż przykładową odpowiedź

Przed odczytem danych po zdobyciu nośnika lub kopii zapasowej (kradzież dysku, nieuprawniony dostęp do plików). Nie chroni przed legalnym użytkownikiem bazy z uprawnieniami do odczytu.

Sprawdź się — zadanie 2

Jak wymusić, aby konto aplikacji łączyło się wyłącznie przez szyfrowane połączenie?

Pokaż przykładową odpowiedź

Przez opcję REQUIRE SSL (lub REQUIRE X509) na koncie oraz włączenie TLS na serwerze, najlepiej z minimalną wersją TLS 1.2.

Lekcja 27 · Część E

Audyt, wyzwalacze i monitorowanie zdarzeń

ŹródłoZawartość
Dziennik błędówawarie, uruchomienia, błędy zasobów
Log wolnych zapytańkosztowne zapytania
Log ogólny (general log)wszystkie zapytania (duży narzut, tylko na czas diagnostyki)
Wtyczka audytukto, skąd i co wykonał: MariaDB Audit Plugin, pgaudit w PostgreSQL
Włączenie audytu logowań i zmian struktur (MariaDB Audit Plugin)
[mysqld]
plugin_load_add = server_audit
server_audit_logging = ON
server_audit_events  = CONNECT,QUERY_DDL,QUERY_DCL
server_audit_file_path = /var/log/mysql/audit.log

Wyzwalacz audytowy

Zapisywanie zmian ocen: kto, kiedy, stara i nowa wartość
CREATE TABLE oceny_audyt (
  id       BIGINT AUTO_INCREMENT PRIMARY KEY,
  ocena_id INT NOT NULL,
  stara    DECIMAL(2,1),
  nowa     DECIMAL(2,1),
  zmienil  VARCHAR(100) NOT NULL,
  kiedy    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

DELIMITER //
CREATE TRIGGER trg_oceny_audyt AFTER UPDATE ON oceny
FOR EACH ROW
BEGIN
  IF OLD.ocena <> NEW.ocena THEN
    INSERT INTO oceny_audyt (ocena_id, stara, nowa, zmienil)
    VALUES (OLD.id, OLD.ocena, NEW.ocena, CURRENT_USER());
  END IF;
END//
DELIMITER ;

Nietypowe wzorce wskazujące na naruszenia

WzorzecMożliwe znaczenie
bardzo duże SELECT bez WHERE na tabelach z danymi osobowymieksfiltracja danych
SELECT ... INTO OUTFILE, wywołania mariadb-dump przez nietypowe kontokopiowanie danych poza bazę
zapytania w nocy lub z nowego adresu IPprzejęte konto
wiele Access deniedzgadywanie haseł
nowe konta, GRANT, zmiany DDLeskalacja uprawnień, zmiana schematu

Dla zdarzeń krytycznych (awaria serwera, brak miejsca, nietypowy wzrost nieudanych logowań) skonfiguruj automatyczne alarmy: wysyłanie logów do systemu SIEM i powiadomienia e-mail lub komunikator.

Sprawdź się — zadanie 1

Do czego służy wyzwalacz audytowy?

Pokaż przykładową odpowiedź

Automatycznie zapisuje szczegóły zmian w ważnych tabelach (kto, kiedy, jaka stara i nowa wartość), co zapewnia rozliczalność i ułatwia wykrycie nieuprawnionych modyfikacji.

Sprawdź się — zadanie 2

Który wzorzec w logach zapytań może wskazywać na próbę wyprowadzenia danych z bazy?

Pokaż przykładową odpowiedź

Bardzo duże zapytania odczytujące całe tabele z danymi osobowymi (zwłaszcza w nietypowych godzinach lub z nowego konta) oraz użycie eksportu do pliku.

Lekcja 28 · Część E

Utwardzanie serwera bazy danych

Utwardzanie bazy to systematyczne ograniczanie jej powierzchni ataku i usuwanie niebezpiecznych ustawień domyślnych.

ObszarDziałanie
Kontausuń anonimowych użytkowników i bazę test; sprawdź konta bez hasła i konta domyślne; ogranicz root do dostępu lokalnego
Siećbind-address na potrzebny interfejs, zapora: port bazy tylko z serwerów aplikacji; zablokuj nieużywane porty i funkcje sieciowe
Funkcjewyłącz local_infile, ogranicz FILE i ustaw secure_file_priv, skip_symbolic_links, usuń nieużywane wtyczki i komponenty
SzyfrowanieTLS co najmniej 1.2, szyfrowanie danych i kopii
Aktualizacjestosuj poprawki bezpieczeństwa, używaj wspieranych wersji
Zgodnośćporównaj konfigurację z benchmarkiem (np. CIS Benchmark dla MySQL/PostgreSQL)
Przegląd kont i sesji
SELECT user, host, plugin, password_expired FROM mysql.user;
SELECT user, host FROM mysql.user WHERE user = '' OR host = '%';      -- anonimowi i konta z dowolnego adresu
SHOW FULL PROCESSLIST;                                                   -- aktywne sesje
SHOW GRANTS FOR 'app'@'10.0.20.%';
Fragment utwardzonej konfiguracji
[mysqld]
bind-address        = 10.0.20.10
local_infile        = 0
skip_symbolic_links = 1
secure_file_priv    = /var/lib/mysql-files
tls_version         = TLSv1.2,TLSv1.3
sql_mode            = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
Regularny przegląd

Co jakiś czas sprawdzaj: konta domyślne i nieużywane, aktywne sesje, zgodność z benchmarkiem, brakujące poprawki, wersje TLS i stan kopii. Zmiany wprowadzaj kontrolowanie i dokumentuj.

Sprawdź się — zadanie 1

Dlaczego usuwa się anonimowych użytkowników i bazę testową?

Pokaż przykładową odpowiedź

Anonimowe konta i baza test dają dostęp bez prawdziwego uwierzytelnienia, co ułatwia atakującemu uzyskanie pierwszego kontaktu z bazą.

Sprawdź się — zadanie 2

Do czego służy ustawienie local_infile = 0?

Pokaż przykładową odpowiedź

Wyłącza możliwość wczytywania plików z klienta poleceniem LOAD DATA LOCAL, co ogranicza ryzyko ataków polegających na odczycie plików z maszyny klienta lub serwera.

Zadanie praktyczne

Utwardzenie serwera bazy i audyt uprawnień

Szacowany czas: 75 minZakres: Lekcje 23–28Forma: raport przed i po utwardzaniu

Zadanie

Na maszynie testowej z serwerem MariaDB lub PostgreSQL przeprowadź przegląd bezpieczeństwa i wprowadź poprawki.

Założenia

  • Zapisz stan wyjściowy: lista kont i uprawnień, nasłuch sieciowy, ustawienia TLS, włączone funkcje (local_infile).
  • Utwórz role aplikacja, raport i administrator_danych z zasadą najmniejszych uprawnień oraz konta przypisane do tych ról.
  • Wymuś TLS dla konta aplikacji, ogranicz adresy kont i ustaw limity połączeń.
  • Dodaj wyzwalacz audytowy dla wybranej tabeli i włącz wtyczkę audytu. Zademonstruj wpis po zmianie danych.
  • Usuń konta domyślne i zbędne funkcje, ustaw nasłuch i zaporę; powtórz przegląd i opisz różnice (raport 1–2 strony).

Ocenie podlegać będzie

  • poprawny model ról i uprawnień,
  • wymuszone szyfrowanie połączeń,
  • działający audyt (wyzwalacz i dziennik),
  • poprawne utwardzenie konfiguracji,
  • czytelny raport przed i po.
Wskazówki
  • Korzystaj z poleceń w lekcjach 23–28.
  • Zmiany w konfiguracji wykonuj po kopii pliku i testuj ponowne uruchomienie serwera.
  • Nie używaj kont i haseł z innych systemów.

Część F

SQL Injection

Mechanizm i rodzaje ataku, identyfikacja podatnego kodu, zapytania przygotowane, walidacja, minimalne uprawnienia i testy bezpieczeństwa.

Lekcja 29 · Część F

SQL Injection: mechanizm i skutki

SQL Injection (wstrzyknięcie SQL) to atak, w którym dane wprowadzone przez użytkownika są interpretowane jako część polecenia SQL. Powstaje, gdy aplikacja buduje zapytanie przez sklejanie tekstów z danymi z formularza, adresu URL, nagłówka lub ciasteczka. Znajduje się w kategorii Injection listy OWASP Top 10.

Podatny kod (Python) i wynikowe zapytanie
login = request.form["login"]
haslo = request.form["haslo"]
zapytanie = "SELECT id FROM uzytkownicy WHERE login = '" + login + "' AND haslo = '" + haslo + "'"
cursor.execute(zapytanie)

# Dane wpisane w formularzu: login:  admin' --   hasło: dowolne
# Zapytanie po sklejeniu:
SELECT id FROM uzytkownicy WHERE login = 'admin' -- ' AND haslo = 'dowolne'
# „--” zaczyna komentarz: sprawdzenie hasła zostało pominięte
RodzajOpis
In-band (error-based, UNION)wynik lub błędy zwracane w odpowiedzi aplikacji; UNION dołącza dane z innych tabel
Blind (boolean, time-based)aplikacja nie pokazuje wyniku; atakujący wnioskuje z różnic w odpowiedzi lub w czasie
Out-of-banddane przekazywane innym kanałem (np. zapytanie sieciowe z serwera bazy)
Drugiego rzędu (second-order)złośliwy tekst zostaje zapisany w bazie i zadziała dopiero przy późniejszym użyciu

Skutki

  • obejście logowania i uzyskanie dostępu do cudzych kont,
  • odczyt całej bazy (dane osobowe, hasła, dane finansowe),
  • zmiana lub usunięcie danych,
  • przy nadmiernych uprawnieniach konta bazy: odczyt plików, wykonanie poleceń na serwerze, przejęcie hosta.
Prawo i etyka

Przykłady służą do rozpoznania i naprawy luk. Testowanie cudzych aplikacji bez zgody jest przestępstwem. Ćwiczenia wykonuj wyłącznie na własnych lub celowo podatnych aplikacjach w izolowanym laboratorium.

Sprawdź się — zadanie 1

Na czym polega SQL Injection?

Pokaż przykładową odpowiedź

Dane wejściowe użytkownika są wklejane do tekstu zapytania SQL i interpretowane jako jego część, więc atakujący może zmienić logikę zapytania (np. pominąć sprawdzenie hasła lub odczytać inne dane).

Sprawdź się — zadanie 2

Jaki jest skutek wprowadzenia loginu admin' -- w podatnym zapytaniu z kluczem login/hasło?

Pokaż przykładową odpowiedź

Znaki „--” rozpoczynają komentarz SQL, więc warunek na hasło zostaje pominięty i atakujący może zalogować się jako admin bez hasła.

Lekcja 30 · Część F

Identyfikacja miejsc podatnych na wstrzykiwanie SQL

Podatności szuka się w kodzie źródłowym (przegląd kodu, analiza statyczna) i w działającej aplikacji. Wzorzec jest zawsze ten sam: dane od użytkownika trafiają do zapytania bez parametryzacji.

Wzorzec w kodzieDlaczego ryzykowny
sklejanie tekstu: "... WHERE id = " + id, f"...{login}..."dane stają się częścią polecenia
interpolacja zmiennych w PHP: "SELECT ... '$login'"jak wyżej
dynamiczny ORDER BY lub nazwa kolumny z parametruparametry zapytania nie obejmują identyfikatorów
listy IN (...) budowane z tekstułatwo pominąć wiązanie wartości
surowe zapytania w ORM (raw, nativeQuery)ORM nie chroni przed konkatenacją
dane zapisane wcześniej, użyte później w zapytaniuwstrzyknięcie drugiego rzędu
Szybkie wyszukiwanie podejrzanych miejsc w kodzie
grep -rnE "(query|execute|exec)\(.*(\+|\$|\{)" --include=*.py --include=*.php --include=*.java .
grep -rnE "SELECT .*\$_(GET|POST|REQUEST)" --include=*.php .

W aplikacji działającej źródłem wejścia są wszystkie dane od klienta: pola formularzy, parametry URL, nagłówki HTTP (np. User-Agent), ciasteczka, treść JSON. Każde z nich trzeba traktować jako niezaufane.

Sprawdź się — zadanie 1

Dlaczego nazwy kolumn w ORDER BY nie można przekazać jako zwykły parametr zapytania?

Pokaż przykładową odpowiedź

Parametry zapytania zastępują wartości, a nie identyfikatory (nazwy kolumn i tabel). Dlatego dynamiczny ORDER BY trzeba zbudować z listy dozwolonych wartości (whitelist).

Sprawdź się — zadanie 2

Wymień trzy źródła niezaufanych danych w aplikacji WWW inne niż pola formularza.

Pokaż przykładową odpowiedź

Parametry adresu URL, nagłówki HTTP (np. User-Agent) i ciasteczka; także dane JSON oraz dane wcześniej zapisane w bazie.

Lekcja 31 · Część F

Parametryzacja zapytań (zapytania przygotowane)

Najskuteczniejszą obroną jest parametryzacja: struktura zapytania i dane są przekazywane oddzielnie. Serwer najpierw otrzymuje wzór zapytania z miejscami na parametry, a wartości traktuje wyłącznie jako dane, nigdy jako kod SQL.

PHP (PDO)
$st = $pdo->prepare('SELECT id, imie FROM uzytkownicy WHERE login = :login AND aktywny = 1');
$st->execute([':login' => $login]);
$uzytkownik = $st->fetch();
Python (mysql-connector lub psycopg2)
cursor.execute("SELECT id FROM uzytkownicy WHERE login = %s AND aktywny = %s", (login, 1))
Java (JDBC)
PreparedStatement ps = conn.prepareStatement("SELECT id FROM uzytkownicy WHERE login = ?");
ps.setString(1, login);
ResultSet rs = ps.executeQuery();
Dynamiczny ORDER BY z listą dozwolonych wartości (Python)
DOZWOLONE = {"nazwisko": "nazwisko", "klasa": "klasa_id", "data": "utworzono"}
kolumna = DOZWOLONE.get(request.args.get("sort"), "nazwisko")
cursor.execute(f"SELECT imie, nazwisko FROM uczniowie ORDER BY {kolumna}")   # kolumna pochodzi z naszej listy, nie od użytkownika
Dlaczego to działa

Nawet jeśli użytkownik wpisze ' OR '1'='1, serwer porówna kolumnę z tym tekstem, a nie wykona go jako polecenie. W PDO ustaw ATTR_EMULATE_PREPARES na false, aby korzystać z prawdziwych zapytań przygotowanych serwera.

Sprawdź się — zadanie 1

Co zmienia się w sposobie przesyłania zapytania, gdy użyjemy zapytań przygotowanych?

Pokaż przykładową odpowiedź

Szkielet zapytania i wartości parametrów są przekazywane oddzielnie, więc wartości są traktowane wyłącznie jako dane i nie mogą zmienić struktury zapytania.

Sprawdź się — zadanie 2

Jak bezpiecznie obsłużyć sortowanie według kolumny wybranej przez użytkownika?

Pokaż przykładową odpowiedź

Przez porównanie wartości z listą dozwolonych kolumn (whitelist) i użycie nazwy kolumny z tej listy, a nie tekstu przesłanego przez użytkownika.

Lekcja 32 · Część F

Walidacja, minimalne uprawnienia i ograniczanie skutków

Parametryzacja jest podstawą, ale bezpieczna aplikacja stosuje obronę warstwową:

WarstwaDziałanie
Parametryzacjapodstawowa ochrona przed SQL Injection
Walidacja wejściasprawdzanie typu, długości, formatu i zakresu po stronie serwera (np. identyfikator to liczba całkowita, e-mail ma poprawny format); whitelist zamiast listy zakazanych znaków
Kodowanie i sanityzacjaoczyszczanie danych tam, gdzie parametryzacja nie jest możliwa; escaping jest ostatecznością, nie zamiennikiem parametrów
Minimalne uprawnienia konta aplikacjibrak DROP, FILE, praw administratora; osobne konto tylko do odczytu
Procedury składowanepomagają, o ile same nie budują zapytań z tekstu
Obsługa błędówużytkownik widzi ogólny komunikat, szczegóły błędu SQL trafiają do dziennika
WAF i monitorowaniedodatkowa warstwa wykrywania, nie zastępuje poprawek w kodzie
Konto aplikacji z minimalnymi uprawnieniami
CREATE USER 'app_szkola'@'10.0.20.5' IDENTIFIED BY '...';
GRANT SELECT, INSERT, UPDATE ON szkola.oceny TO 'app_szkola'@'10.0.20.5';
GRANT SELECT ON szkola.uczniowie TO 'app_szkola'@'10.0.20.5';
Błędy ujawniające informacje

Komunikaty SQL pokazywane użytkownikowi (nazwy tabel, zapytania, wersja serwera) ułatwiają atak. W środowisku produkcyjnym wyłącz szczegółowe komunikaty i zapisuj je tylko w dzienniku.

Sprawdź się — zadanie 1

Dlaczego nie wystarczy filtrowanie apostrofów w danych wejściowych?

Pokaż przykładową odpowiedź

Listy zakazanych znaków są łatwe do obejścia (kodowania, inne konstrukcje), a nie wszystkie ataki używają apostrofów. Pewną ochroną jest parametryzacja, a walidacja whitelist jest uzupełnieniem.

Sprawdź się — zadanie 2

Jak ograniczenie uprawnień konta aplikacji zmniejsza skutki udanego SQL Injection?

Pokaż przykładową odpowiedź

Atakujący może wykonać tylko operacje dostępne dla konta: bez DROP, FILE czy praw administratora nie usunie tabel ani nie odczyta plików serwera, a szkody ograniczą się do wskazanych tabel.

Lekcja 33 · Część F

Testowanie pod kątem SQL Injection i weryfikacja poprawek

Testy bezpieczeństwa sprawdzają, czy aplikacja jest odporna na wstrzykiwanie SQL. Wykonuje się je wyłącznie za zgodą właściciela i w środowisku testowym, np. na celowo podatnej aplikacji w izolowanym laboratorium.

Rodzaj testuOpis
Przegląd kodu (SAST)wyszukiwanie sklejania tekstów w zapytaniach ręcznie i narzędziami analizy statycznej
Testy ręcznewprowadzenie w pola apostrofu ' lub cudzysłowu i obserwacja błędów lub zmian w odpowiedzi, proste warunki logiczne (' OR '1'='1) w środowisku testowym
Testy automatyczne (DAST)skanery aplikacji webowych i narzędzia specjalistyczne używane w laboratorium, np. sqlmap, wyłącznie na zgodnych celach
Testy jednostkowe i regresjidodawanie przypadków ze „złośliwymi” danymi do zestawu testów, aby poprawka nie została cofnięta
Przykład testu jednostkowego po poprawce (Python, pytest)
def test_logowanie_odporne_na_sqli(baza_testowa):
    wynik = zaloguj("admin' OR '1'='1", "dowolne")
    assert wynik is None            # logowanie nie może się udać

def test_logowanie_poprawne(baza_testowa):
    assert zaloguj("anna", "PoprawneHaslo!1") is not None

Naprawa i weryfikacja

  • napraw przyczynę (parametryzacja), a nie objawy (filtr znaków),
  • ponów ten sam test, który wykrył lukę, i sprawdź, że już nie działa,
  • dodaj test regresji i opisz zmianę w dokumentacji,
  • zbadaj podobne miejsca w kodzie (ta sama luka często powtarza się w wielu zapytaniach).
Sprawdź się — zadanie 1

Jak sprawdzisz, że poprawka usunęła podatność na SQL Injection?

Pokaż przykładową odpowiedź

Powtarzam test, który wykazał podatność, i potwierdzam, że atak już nie działa, a normalne funkcje aplikacji nadal działają. Dodaję test regresji do zestawu testów.

Sprawdź się — zadanie 2

Dlaczego testy penetracyjne aplikacji wykonuje się za zgodą właściciela i w środowisku testowym?

Pokaż przykładową odpowiedź

Testy bez zgody mogą naruszać prawo (np. art. 267 k.k.), a na systemie produkcyjnym mogą uszkodzić dane lub zakłócić działanie usług.

Zadanie praktyczne

Naprawa podatnej aplikacji

Szacowany czas: 75 minZakres: Lekcje 29–33Forma: kod, testy i raport

Zadanie

Otrzymujesz prostą aplikację WWW (PHP lub Python) z formularzem logowania i wyszukiwarką uczniów, w której zapytania SQL są budowane przez sklejanie tekstów. Pracujesz w izolowanym laboratorium.

Założenia

  • Znajdź w kodzie wszystkie miejsca podatne na SQL Injection i opisz każde (źródło danych, zapytanie, ryzyko).
  • Zademonstruj lukę w środowisku testowym (np. obejście logowania prostym wzorcem) i opisz skutek.
  • Napraw kod: zapytania przygotowane, lista dozwolonych wartości dla sortowania, walidacja typów, ogólne komunikaty błędów.
  • Utwórz osobne konto bazy dla aplikacji z minimalnymi uprawnieniami i zastosuj je.
  • Napisz testy (przynajmniej 3 przypadki z „złośliwymi” danymi) potwierdzające, że luka została usunięta, i krótki raport.

Ocenie podlegać będzie

  • pełna lista podatnych miejsc,
  • poprawna parametryzacja i walidacja,
  • konto z minimalnymi uprawnieniami,
  • skuteczne testy regresji,
  • jakość raportu.
Wskazówki
  • Wzorce poszukiwań w lekcji 30, przykłady poprawek w lekcji 31.
  • Pamiętaj o sortowaniu: nazwy kolumn nie przekazuje się jako parametry.
  • Środowisko ćwiczeniowe musi być odizolowane od sieci szkolnej.

Część G

Bazy nierelacyjne (NoSQL)

Rodzaje i cechy NoSQL, MongoDB i CRUD, projekt dokumentów, bezpieczeństwo, NoSQL injection oraz migracja i dobór technologii.

Lekcja 34 · Część G

Bazy nierelacyjne: rodzaje, cechy i zastosowania

Bazy nierelacyjne (NoSQL) to systemy, które nie opierają się na tabelach z rygorystycznym schematem. Powstały, by obsługiwać duże ilości danych o zmiennej strukturze i skalować się poziomo (przez dodawanie serwerów).

RodzajModel danychPrzykładyZastosowania
Dokumentowedokumenty podobne do JSONMongoDB, CouchDBkatalogi produktów, profile użytkowników, treści
Klucz-wartośćpara klucz i wartośćRedispamięć podręczna, sesje, liczniki
Kolumnowe (rodzin kolumn)szerokie wiersze, kolumny w rodzinachCassandradane czasowe, logi na dużą skalę
Grafowewęzły i krawędzieNeo4jsieci powiązań, rekomendacje, wykrywanie oszustw
CechaRelacyjne (SQL)Nierelacyjne (NoSQL)
Schematsztywny, zdefiniowany z góryelastyczny, często dowolny
Relacje i złączeniamocne (klucze obce, JOIN)ograniczone; dane często osadzane w dokumentach
Spójnośćpełne transakcje ACIDróżnie; często spójność ostateczna (podejście BASE), nowsze systemy wspierają transakcje
Skalowaniegłównie pionowenaturalnie poziome
ZapytaniaSQL, złożone analizyjęzyk specyficzny dla systemu
Jak wybierać

Relacyjna baza: dane silnie powiązane, transakcje, raporty i złożone zapytania (finanse, ewidencje). NoSQL: elastyczna lub zmienna struktura, bardzo duża skala odczytów i zapisów, szybkie prototypowanie. Wiele systemów łączy oba podejścia (poliglotyczna persystencja).

Sprawdź się — zadanie 1

Podaj przykład zastosowania bazy klucz-wartość.

Pokaż przykładową odpowiedź

Pamięć podręczna (cache) i przechowywanie sesji użytkowników, np. w systemie Redis, ze względu na bardzo szybkie odczyty po kluczu.

Sprawdź się — zadanie 2

Czym różni się podejście do schematu w bazie dokumentowej i relacyjnej?

Pokaż przykładową odpowiedź

W relacyjnej schemat jest ściśle zdefiniowany z góry (kolumny i typy). W dokumentowej poszczególne dokumenty w kolekcji mogą mieć różną strukturę, co daje elastyczność, ale wymaga dyscypliny i walidacji.

Lekcja 35 · Część G

MongoDB: kolekcje, dokumenty i operacje CRUD

W MongoDB dane są zapisane w dokumentach (format BSON, odpowiednik JSON z dodatkowymi typami), pogrupowanych w kolekcje, a kolekcje w bazach. Każdy dokument ma unikalne pole _id. Pracę wykonuje się np. w konsoli mongosh.

Pojęcie relacyjneOdpowiednik w MongoDB
baza danychbaza danych
tabelakolekcja
wierszdokument
kolumnapole dokumentu
klucz głównypole _id
Operacje CRUD w mongosh
use szkola

// Create
db.uczniowie.insertOne({ imie: "Anna", nazwisko: "Kowalska", klasa: "2A",
                         oceny: [ { przedmiot: "Sieci", ocena: 5 }, { przedmiot: "Bazy", ocena: 4 } ] })
db.uczniowie.insertMany([ { imie: "Jan", nazwisko: "Nowak", klasa: "2A" } ])

// Read
db.uczniowie.find({ klasa: "2A" }, { imie: 1, nazwisko: 1, _id: 0 })
db.uczniowie.find({ "oceny.ocena": { $gte: 5 } })
db.uczniowie.countDocuments({ klasa: "2A" })

// Update
db.uczniowie.updateOne({ imie: "Anna" }, { $set: { klasa: "3A" } })

// Delete
db.uczniowie.deleteOne({ imie: "Jan" })
OperatorZnaczenie
$eq, $nerówny, różny
$gt, $gte, $lt, $ltewiększy, większy lub równy, mniejszy, mniejszy lub równy
$in, $ninw zbiorze, poza zbiorem
$and, $orkoniunkcja i alternatywa warunków
$set, $inc, $pushustawienie pola, zwiększenie liczby, dodanie do tablicy
Sprawdź się — zadanie 1

Jak w MongoDB odpowiada się pojęciu tabeli i wiersza?

Pokaż przykładową odpowiedź

Tabeli odpowiada kolekcja, a wierszowi dokument (w formacie BSON/JSON).

Sprawdź się — zadanie 2

Który operator wybierze uczniów z oceną co najmniej 5 w tablicy ocen?

Pokaż przykładową odpowiedź

db.uczniowie.find({ "oceny.ocena": { $gte: 5 } }).

Lekcja 36 · Część G

Projektowanie dokumentów, JSON/BSON i walidacja schematu

W bazach dokumentowych projekt zależy od sposobu odczytu danych. Główna decyzja to osadzanie (embedding) czy odwołania (references).

PodejścieKiedy stosowaćPrzykład
Osadzaniedane zawsze czytane razem, relacja 1:kilka, dane niezbyt rosnąceoceny ucznia wewnątrz dokumentu ucznia
Odwołaniadane duże lub rosnące bez ograniczeń, współdzielone przez wiele dokumentówklasa_id wskazujący dokument klasy; logi w osobnej kolekcji
  • rozmiar jednego dokumentu jest ograniczony (w MongoDB do 16 MB), więc nie osadzaj list rosnących bez końca,
  • BSON rozszerza JSON o typy: data, ObjectId, Decimal128 (dokładne liczby dziesiętne), dane binarne,
  • pola, po których szukasz, wymagają indeksów: db.uczniowie.createIndex({ nazwisko: 1 }).
Walidacja schematu w kolekcji ($jsonSchema)
db.createCollection("uczniowie", {
  validator: { $jsonSchema: {
    bsonType: "object",
    required: ["imie", "nazwisko", "klasa"],
    properties: {
      imie:     { bsonType: "string", maxLength: 50 },
      nazwisko: { bsonType: "string", maxLength: 80 },
      klasa:    { bsonType: "string", pattern: "^[1-5][A-Z]$" }
    }
  } },
  validationAction: "error"
})
Elastyczność ma cenę

Brak sztywnego schematu nie oznacza braku dyscypliny. Walidacja schematu i indeksy pomagają zachować poprawność i wydajność danych w kolekcji.

Sprawdź się — zadanie 1

Kiedy lepiej osadzić dane w dokumencie, a kiedy użyć odwołania?

Pokaż przykładową odpowiedź

Osadzam, gdy dane są zawsze czytane razem i nie rosną w nieskończoność. Używam odwołań dla danych dużych, rosnących lub współdzielonych przez wiele dokumentów.

Sprawdź się — zadanie 2

Do czego służy walidacja $jsonSchema?

Pokaż przykładową odpowiedź

Wymusza strukturę i typy pól w dokumentach kolekcji (pola wymagane, typy, długości, wzorce), co chroni przed zapisem niepoprawnych danych.

Lekcja 37 · Część G

Bezpieczeństwo baz nierelacyjnych

Wiele wycieków danych dotyczyło baz NoSQL wystawionych do internetu bez uwierzytelniania. Starsze instalacje i niektóre domyślne konfiguracje nie wymuszały haseł, więc każdy, kto znalazł otwarty port, miał pełny dostęp.

MongoDB: bezpieczna konfiguracja (mongod.conf)
net:
  port: 27017
  bindIp: 127.0.0.1
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/tls/server.pem
security:
  authorization: enabled
Konto z najmniejszymi uprawnieniami
use szkola
db.createUser({
  user: "app_szkola",
  pwd: passwordPrompt(),
  roles: [ { role: "readWrite", db: "szkola" } ]
})
ObszarZalecenie
Uwierzytelnianiewłącz authorization, silne hasła, konta imienne dla administratorów
Role (RBAC)najmniejsze uprawnienia: read lub readWrite na jedną bazę zamiast root
SiećbindIp na potrzebny interfejs, zapora, brak dostępu z internetu
SzyfrowanieTLS w ruchu, szyfrowanie danych w spoczynku, szyfrowane kopie
Audyt i logiwłącz audyt (w edycjach wspierających) i monitoruj logowania oraz zmiany uprawnień
Aktualizacjestosuj poprawki, używaj wspieranych wersji

Wstrzykiwanie w bazach NoSQL

NoSQL injection polega na przekazaniu w danych wejściowych operatorów zapytania, które zmieniają jego sens. Gdy aplikacja wstawia do zapytania obiekt z żądania bez sprawdzenia typu, atakujący może przesłać zamiast hasła obiekt z operatorem.

Podatne zapytanie i atak (JSON w żądaniu)
// aplikacja: db.uzytkownicy.findOne({ login: req.body.login, haslo: req.body.haslo })

// dane w żądaniu:  { "login": "admin", "haslo": { "$ne": null } }
// powstaje warunek: haslo różne od null, czyli prawdziwy dla każdego konta
  • waliduj typy: login i hasło muszą być tekstem, a nie obiektem,
  • nie przechowuj haseł w jawnej postaci (skrót z solą), więc porównuje się je w aplikacji, a nie w zapytaniu,
  • unikaj operatorów wykonujących kod ($where, JavaScript po stronie serwera),
  • używaj bibliotek mapujących i walidujących dane wejściowe.
Sprawdź się — zadanie 1

Jaka była częsta przyczyna wycieków z baz MongoDB w internecie?

Pokaż przykładową odpowiedź

Serwer bazy był dostępny z internetu bez włączonego uwierzytelniania (brak haseł), więc każdy mógł odczytać i zmienić dane.

Sprawdź się — zadanie 2

Na czym polega NoSQL injection z operatorem $ne?

Pokaż przykładową odpowiedź

Atakujący przesyła w polu zamiast tekstu obiekt z operatorem (np. { "$ne": null }), który sprawia, że warunek jest prawdziwy dla każdego konta. Obrona: walidacja typu danych wejściowych.

Lekcja 38 · Część G

Migracja i integracja SQL z NoSQL oraz dobór technologii

Dane często trzeba przenieść z bazy relacyjnej do dokumentowej (lub połączyć obie). Narzędzia AI mogą zaproponować mapowanie schematu, skrypt migracji i przykładowe zapytania, ale wynik wymaga dokładnej kontroli.

Krok migracjiCo sprawdzić
Mapowanie schematutabele → kolekcje; klucze obce → osadzanie lub odwołania; tabele łączące → tablice
Typy danychDECIMAL → Decimal128 (nie zwykła liczba zmiennoprzecinkowa); daty i strefy czasowe
Spójnośćliczba rekordów przed i po migracji, losowe porównania, sumy kontrolne
Powiązaniaczy odwołania wskazują istniejące dokumenty
Dane wrażliwenie wysyłaj prawdziwych danych do zewnętrznych narzędzi AI; użyj danych zanonimizowanych lub samego schematu
Bezpieczeństwouprawnienia kont migracji, szyfrowanie transportu, usunięcie plików pośrednich po migracji
Przykładowy plan migracji (szkic)
-- 1. eksport z SQL do JSON (np. przez zapytanie JSON_OBJECT lub skrypt w Pythonie)
-- 2. walidacja: liczba rekordów w tabeli = liczba dokumentów w kolekcji
-- 3. import do MongoDB: mongoimport --db szkola --collection uczniowie --file uczniowie.json --jsonArray
-- 4. porównanie wyników zapytań w obu systemach na próbce

Dobór technologii do wymagań

PytanieSkłania ku relacyjnejSkłania ku NoSQL
Struktura danychstała, dobrze znanazmienna, półstrukturalna
Transakcje wielu rekordówkluczowe (finanse, rejestry)rzadko potrzebne
Powiązania i raportyzłożone zapytania, JOIN-yodczyt całych obiektów naraz
Skalaumiarkowanabardzo duża, rozproszona
Kompetencje zespołudobra znajomość SQLdoświadczenie z danym systemem NoSQL
Sprawdź się — zadanie 1

Co należy zweryfikować po migracji danych z bazy relacyjnej do dokumentowej?

Pokaż przykładową odpowiedź

Zgodność liczby rekordów, poprawność typów (np. dokładne liczby dziesiętne, daty), spójność powiązań, wyniki zapytań na próbkach oraz brak utraty lub zniekształcenia danych.

Sprawdź się — zadanie 2

Kiedy projekt powinien pozostać przy bazie relacyjnej?

Pokaż przykładową odpowiedź

Gdy dane są silnie powiązane, struktura jest stała, a kluczowe są transakcje ACID, spójność i złożone raporty (np. systemy finansowe, ewidencje).

Zadanie praktyczne

Projekt hybrydowy: baza relacyjna i dokumentowa

Szacowany czas: 90 minZakres: Lekcje 34–38Forma: projekt, zapytania i dokumentacja

Zadanie

Dla aplikacji szkolnej z lekcji poprzednich zaprojektuj rozwiązanie wykorzystujące bazę relacyjną dla ewidencji (uczniowie, oceny) i dokumentową dla materiałów i aktywności (np. wiadomości, wpisy aktywności ucznia).

Założenia

  • Uzasadnij podział: które dane trafią do SQL, a które do MongoDB (3–5 zdań).
  • Zainstaluj MongoDB w środowisku testowym, włącz uwierzytelnianie i utwórz konto z rolą readWrite na jedną bazę.
  • Zaprojektuj dokumenty (osadzanie lub odwołania), dodaj walidację $jsonSchema i indeks.
  • Wykonaj operacje CRUD i jedną migrację fragmentu danych z SQL do MongoDB; zweryfikuj liczbę rekordów.
  • Opisz zagrożenia (NoSQL injection, otwarty dostęp) i zabezpieczenia oraz napisz test, który odrzuci hasło przesłane jako obiekt z operatorem.

Ocenie podlegać będzie

  • sensowne uzasadnienie podziału danych,
  • bezpieczna konfiguracja i konto,
  • poprawny projekt dokumentów i walidacja,
  • udana i zweryfikowana migracja,
  • trafny opis zagrożeń i zabezpieczeń.
Wskazówki
  • Skorzystaj z przykładów w lekcjach 35–38.
  • Pamiętaj o wiązaniu serwera tylko z adresem lokalnym i TLS poza laboratorium.
  • Do migracji użyj danych testowych.