
Event Listener to tylko warstwa pośrednicząca
Jak pisać Event Listenery by były przyjazne i nie nastręczały nam problemów? Najpierw trzeba zrozumieć czym one tak na prawdę są i jaką mają odpowiedzialność.
Ten krótki artykuł przyszedł mi do głowy gdy na pewnym forum ktoś zadał pytanie dotyczące tego, jakich danych nie powinno się przechowywać w sesji. Chciałbym pokrótce opisać niektóre z tych danych oraz dodać kilka kwestii od siebie. Zaczynajmy.
To chyba najmniej pożądane dane, które chcielibyśmy widzieć w sesji, jednak nadal zdażają się aplikacje, które te dane przechowują (i wierz mi lub nie, ale szyfrowanie danych, podobnie jak ciasteczek w Laravelu, to nie jest zabezpieczenie :)). Dane do logowania są potrzebne tylko i wyłącznie podczas logowania, jeśli potrzebujesz sprawdzić czy użytkownik jest zalogowany lub nie, należy dodać kolejne warstwy aplikacji, które te operacje wykonają w sposób bezpieczny.
Do tego punktu można podpiąć wszystkie przypadki w których mamy do czynienia z jakimikolwiek kluczami szyfrowania, czy identyfikatorami prywatnymi, które nie powinny ujrzeć światła dziennego.
W przypadku niektórych aplikacji polecam zapoznać się z komponentami Symfony z rodziny security, które upraszczają wiele rzeczy.
Wyobraź sobie koszyk w aplikacji, gdzie w sesji przechowywane są produkty dodane do tego koszyka. W przypadku gdy cały koszyk zostanie zapisany do sesji, to w sesji zapisane zostaną pełnoprawne obiekty aplikacji. Dane sesyjne są serializowane w większości przypadków, więc podczas odczytywania sesji w kolejnym requeście dostaniesz te obiekty już uzupełnione – bardzo pożyteczne. Jednak co jeśli w tym czasie zmieni się cokolwiek w tej klasie, dodasz lub zmienisz jakąś właściwość, albo co gorsza – zmienisz jej nazwę? Podczas odserializowania danych, przy braku klasy obiektu serializowanego zostanie wyrzucony błąd, który może rozsypać aplikację na dobre. Aplikacja w takim stanie może trwać tak długo, aż ostatni z użytkowników nie zakończy sesji.
Ciężki przypadek do debugowania – nie będziesz w stanie zreprodukować tego błędu ponieważ nie będziesz posiadał w sesji podobnych danych, które posiada użytkownik, któremu ten błąd się pojawił.
Niby oczywiste, ale mało kiedy się o tym pamięta. Sesja może być przechowywana w naprawdę wielu miejscach – od domyślnego session storage PHP, przez jakąś bazę danych po Redisa. Bez względu na rodzaj miejsca przechowywania danych, zawsze jest jakieś ograniczenie w postaci ilości miejsca które jest na to przeznaczone. Gdy zamieścisz za dużo (niepotrzebnych) danych w sesji, zapisywanie sesji może się nie udać, ponieważ nadmiarowe dane zostanę ucięte. W najgorszych przypadkach, takie sytuacje mogą pociągnąć ze sobą znacznie więcej problemów. Wyobraź sobie, że w sesji przechowywane są dane do logowania i włączone jest środowisko developerskie, na których widać dokładny dump danych, które się nie zapisały. Katastrofa gotowa.
Sesja powinna przechowywać tylko tyle informacji, ile jest potrzebne by użytkownik mógł kontynuować operację w następnym requeście – czytaj: zapamiętanie logowania, produkty w koszyku. Czy przechowywanie opisu i awataru użytkownika w sesji jest potrzebne by zweryfikować czy jest zalogowany?
Wyobraź sobie, że potrzebujesz przechować imię i nazwisko, które wprowadził w formularzu na poprzedniej stronie użytkownik, ponieważ proces zakupowy składa się z kilku kroków, a kroki te są rozsypane na kilka podstron. W przypadku gdy użytkownik wprowadzi znaki specjalne, a aplikacja nie będzie w stanie zareagować poprawnie w trakcie serializacji, podczas odserializowania sesji może dojść do malformacji danych i spowodowania błędów, które mogą być ciężkie w konsekwencjach.
Staraj się przechowywać w sesji tylko najpotrzebniejsze dane z zaufanych źródeł, a jeśli zajdzie sytuacja jak z przykładu, staraj się weryfikować dane przed zapisaniem – czy w imieniu i nazwisku ktokolwiek będzie posiadał dwukropek lub podkreślnik?
Polub stronę PHPCenter.pl by zyskać dostęp do najnowszych wiadomości ze świata PHP!
Programista przeważnie wierzy w to, że dane przechowywane w danym miejscu są bezpieczne. Tzn, nikt ich nie zmienił od naszego ostatniego zapisania. O ile przechowywanie danych w jakiejś bazie danych jest w miarę bezpieczne, ponieważ rzadko zmieniamy strukturę tabel nie wykonując migracji przy deploymencie, o tyle przechowywane dane w sesji nie mają z góry ustalonej struktury. Ważne jest by podchodzić do danych z sesji zgodnie z zasadą „ufaj, ale kontroluj”. Jeśli zapisałeś w danym kluczu identyfikator zalogowanego użytkownika, to podczas kolejnego requestu sprawdź czy ten użytkownik faktycznie istnieje w bazie danych. Jeśli przechowujesz listę produktów, sprawdź czy to faktycznie jest tablica, czy każdy produkt faktycznie posiada wymagane klucze i wartości, oraz czy te produkty faktycznie istnieją w bazie danych.
Niby dużo się nie zmieniło od ostatniego requestu, jednak zmienić mogło się wszystko.
W sesji powinny być przechowywane identyfikatory, na przykład ID aktualnie zalogowanego użytkownika. Często również przechowuje się na przykład treść wygenerowanego obrazka CAPTCHA by móc w następnym requeście zweryfikować poprawność wprowadzonych danych. Można również przechowywać większe ilości danych, na przykład identyfikatory produktów z ich ceną w przypadku sklepu, jednak zalecane są tutaj typy proste takie jak array czy string. Główna zasada brzmi – im mniej tym lepiej.
Najlepszym sposobem na przechowywanie danych jest używanie typów prostych, takich jak array, string, integer/float itd. Mamy w tedy pewność, że podczas odczytywania danych nie wystąpią problemy z brakiem/niezgodnością klas i struktur klas w aplikacji.
Sesja ma pomóc w „przenoszeniu” wymaganych danych pomiędzy żądaniami, by nasza aplikacja wiedziała kto otwiera daną/kolejną podstronę. Nie jest ona jednak „bazą danych”, w której możemy przechowywać wszystko co uważamy za potrzebne. Zanim zapiszesz dane w sesji zastanów się, czy ich miejsce jest właśnie tam – być może w ogóle nie są tam potrzebne? Pamiętaj również by trzymać się typów prostych i zawsze weryfikować czy pobierane dane z sesji są prawidłowe.
A czy Ty znasz jeszcze jakieś inne zasady dotyczące przechowywania danych w sesji? Podziel się swoimi uwagami w komentarzu.
Polub naszą stronę aby dostawać powiadomienia o nowych, niesamowitych treściach!