- Tabela odnotowuje zdarzenia dotyczące dostępu, w tym nieudane próby logowania wraz z adresem IP.
- Cztery kolumny wystarczają, żeby rozpoznać próbę odgadnięcia hasła: kto, skąd, kiedy i z jakim skutkiem.
- Rodzaj zdarzenia jest opisany tekstem, nie kodem — daje elastyczność kosztem trudniejszego filtrowania.
- Brak indeksu na kolumnie z czasem sprawia, że zapytania o ostatnią dobę przeglądają całą tabelę.
Do czego służy tabela [dbo].[_users_events]
Włamanie do systemu magazynowego rzadko zaczyna się od wyrafinowanej techniki. Zaczyna się od prób odgadnięcia hasła — kilkudziesięciu, kilkuset, wykonywanych z jednego adresu w krótkim czasie. Tabela [dbo].[_users_events] jest miejscem, w którym takie próby zostawiają ślad.
Struktura jest minimalna i wystarczająca. Nazwa użytkownika, adres IP, czas zdarzenia oraz jego opis — na przykład informacja o błędnym logowaniu. Cztery wartości pozwalają odpowiedzieć na wszystkie pytania istotne przy analizie: czy próby dotyczą jednego konta, czy wielu; czy pochodzą z jednego adresu; jak są rozłożone w czasie.
Rozróżnienie rodzaju zdarzenia zapisano tekstem w kolumnie ZDARZENIE. Daje to swobodę w dodawaniu nowych rodzajów bez zmiany struktury, ale wymaga konsekwencji: zapisy różniące się wielkością liter albo drobnym sformułowaniem trafią do osobnych grup w każdym zestawieniu i zafałszują statystykę.
Rozróżnienie ma znaczenie: próby wobec jednego konta to zwykle zapomniane hasło, wobec wielu — atak słownikowy.
Budowa tabeli — wykaz kolumn
Pięć kolumn opisuje pojedyncze zdarzenie dotyczące dostępu do systemu.
| Kolumna | Typ | Wymagana | Znaczenie |
|---|---|---|---|
CZAS | datetime data i godzina | nie | Czas zdarzenia |
ID_USER_IP | int liczba całkowita | tak | Id wpisu dotyczacego ip |
IP | varchar(50) tekst do 50 znaków | nie | Ip logowania |
USERNAME | varchar(50) tekst do 50 znaków | nie | Nazwa uzytkownika |
ZDARZENIE | varchar(50) tekst do 50 znaków | nie | Opis zdarzenia jakie opisuje dany rekord np. BLEDNE LOGOWANIE |
Kolumna ZDARZENIE ma pięćdziesiąt znaków i przechowuje opis tekstowy. Warto ustalić zamkniętą listę dopuszczalnych wartości — bez tego zestawienia rozbijają się na warianty różniące się wyłącznie zapisem.
Indeksy i wydajność zapytań
Tabela ma zdefiniowany wyłącznie klucz główny, co przy analizie bezpieczeństwa jest ograniczeniem.
| Indeks | Kolumny | Rodzaj |
|---|---|---|
PK__users_events | ID_USER_IP | klucz główny |
Wszystkie sensowne pytania do tej tabeli zawężają zakres czasu albo dotyczą jednego adresu IP, a żadna z tych kolumn nie jest zindeksowana. Przy kilkuset tysiącach wpisów oznacza to, że codzienna kontrola bezpieczeństwa wymaga odczytu całej tabeli. Indeks na parze CZAS i IP rozwiązałby to niewielkim kosztem.
Co widać w rejestrze i jak to interpretować
Nieudane logowanie samo w sobie nic nie znaczy — ludzie mylą hasła codziennie. Znaczenie ma wzorzec, w jakim próby występują.
| Co widać | Prawdopodobne wyjaśnienie | Reakcja |
|---|---|---|
| Kilka prób, jeden login, jeden adres | Zapomniane hasło albo zmiana układu klawiatury | Żadna — sytuacja normalna |
| Kilkadziesiąt prób, jeden login, jeden adres | Próba odgadnięcia hasła do konkretnego konta | Blokada adresu, kontakt z właścicielem konta |
| Wiele loginów, jeden adres | Atak słownikowy na dowolne konto | Natychmiastowa blokada adresu |
| Jeden login, wiele adresów | Udostępnione hasło albo przejęte konto | Wymuszenie zmiany hasła |
| Próby poza godzinami pracy | Dostęp z zewnątrz albo automat | Sprawdzenie, czy adres należy do sieci firmowej |
Trzeci wiersz wymaga reakcji najszybszej — atak obejmujący wiele loginów wskazuje na działanie automatu, nie pomyłkę człowieka.
Warto ustawić na tę tabelę zadanie kontrolne uruchamiane raz dziennie i wysyłające podsumowanie, gdy liczba nieudanych prób z jednego adresu przekroczy ustalony próg. Kilkanaście minut konfiguracji zamienia rejestr z archiwum, do którego nikt nie zagląda, w mechanizm faktycznie ostrzegający — a to różnica między wykryciem problemu w dniu jego wystąpienia a po miesiącu.
Jak korzystać z tabeli w praktyce
Przy korzystaniu z rejestru zdarzeń logowania warto pamiętać o kilku rzeczach:
- Ustal zamkniętą listę wartości kolumny
ZDARZENIE; swobodny tekst rozbija zestawienia na warianty tego samego zdarzenia. - Grupuj po adresie IP, zanim zaczniesz analizować pojedyncze wpisy — wzorzec mówi więcej niż zdarzenie.
- Odróżniaj próby wobec jednego konta od prób wobec wielu; to dwie zupełnie różne sytuacje wymagające różnej reakcji.
- Ustaw automatyczne powiadomienie po przekroczeniu progu prób z jednego adresu, zamiast polegać na ręcznym przeglądzie.
- Rozważ indeks na parze
CZASiIP— obecnie każde zapytanie kontrolne przegląda całą tabelę. - Przechowuj wpisy dłużej niż inne rejestry; analiza bezpieczeństwa często sięga wstecz o miesiące.
Adresy, z których w ciągu ostatniej doby nie powiodło się wiele prób logowania — pierwsza rzecz do sprawdzenia przy kontroli bezpieczeństwa:
SELECT IP,
COUNT(*) AS PROB,
COUNT(DISTINCT USERNAME) AS ROZNYCH_LOGINOW,
MIN(CZAS) AS PIERWSZA,
MAX(CZAS) AS OSTATNIA
FROM dbo._users_events
WHERE ZDARZENIE LIKE '%LOGOWANIE%'
AND CZAS >= DATEADD(DAY, -1, GETDATE())
GROUP BY IP
HAVING COUNT(*) > 10
ORDER BY ROZNYCH_LOGINOW DESC, PROB DESC;
Sortowanie zaczyna się od liczby różnych loginów, nie od liczby prób. Adres atakujący dziesięć kont po pięć razy jest groźniejszy niż ten, który pięćdziesiąt razy próbował dostać się na jedno.
Osobną kwestią jest okres przechowywania. Rejestry operacyjne archiwizuje się zwykle po kilku miesiącach, bo starsze wpisy przestają być potrzebne. Tutaj jest odwrotnie: analiza incydentu bezpieczeństwa niemal zawsze sięga wstecz dalej, niż się początkowo zakłada, a wpisy sprzed pół roku bywają jedynym dowodem na to, kiedy problem naprawdę się zaczął. Warto więc ten jeden rejestr wyłączyć z ogólnej reguły archiwizacji.
Rejestr zdarzeń logowania jest tanim zabezpieczeniem, które działa wyłącznie wtedy, gdy ktoś do niego zagląda — albo gdy zagląda za niego zadanie automatyczne. Bez tego pozostaje zapisem, z którego dowiadujemy się o włamaniu już po fakcie.
Powiązane tabele i dokumentacja
Rejestr zdarzeń logowania czyta się razem z pozostałymi zapisami dotyczącymi dostępu: