Częsty scenariusz:

  1. Użytkownik loguje się na stronie
  2. Cośtam grzebie jako zalogowany
  3. Wylogowuje się
  4. AAAARGH! Może użyć “Wstecz” i zobaczyć stronę na której jest zalogowany!

Otóż przyczyną problemu nie jest możliwość cofania, a niezrozumienie, co “Wstecz” robi. To nie jest nawigacja, a przeglądanie historii. Użytkownik nie może stać się ponownie zalogowany, ale może zobaczyć stronę w stanie gdy był zalogowany.

Kolega powiedział, że to sie blokuje keszem!

Kolega chciał dobrze, ale mu nie wyszło. RFC 2616, 13.13 rzecze tak:

History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.
By default, an expiration time does not apply to history mechanisms. If the entity is still in storage, a history mechanism SHOULD display it even if the entity has expired, unless the user has specifically configured the agent to refresh expired history documents.

co można przetłumaczyć jako:

Historia i cache to osobne mechanizmy. W szczególności mechanizm historii NIE POWINIEN próbować pokazać rzeczywistego stanu danego zasobu. Historia ma za zadanie pokazać dokładnie to, co użytkownik widział, gdy dany zasób został pobrany.
Domyślnie data ważności nie dotyczy historii. Jeśli przeglądarka ma dostęp do kopii danego zasobu POWINNA go wyświetlić, nawet jeśli stracił ważność, chyba że użytkownik umyślnie skonfigurował przeglądarkę, aby odświeżała strony.

Na chłopski rozum: nieważne ile nagłówków cache nawsadzasz, to i tak to nic nie da, bo to z historią walczysz, a nie cache.

Ale będą mi się wstecznie logować i od tyłu hackować!

HTTP jest tranzakcyjnym protokołem, który nie posiada stanów. Oznacza to, że z punktu widzenia HTTP nie istnieje stan zalogowania. Każde żądanie jest niezależne i serwer musi sprawdzać uprawnienia każdego żądania. Jeśli jest inaczej, to jest to ogromny błąd — zabezpieczenie typu “drzwi do lasu” — i blokowanie przeglądarki nic tutaj nie pomoże.

Jak poprawić skrypty z zabezpieczeniami placebo

Nie można zrobić tylko “bramki”, która po sprawdzeniu hasła przekierowuje na tajne strony, bo to zabezpiecza tylko bramkę, a nie strony za nią (a dzięki nagłówkowi Referer te strony tajne długo nie będą). Nie można polegać na prostych rzeczach, jak cookie “zalogowany=tak”, czy nagłówki Referer, bo to (jak wszystko przychodzące od klienta) jest banalnie proste do podrobienia. Trzeba gruntownie sprawdzać autentyczność każdego zapytania do serwera.

Wbudowane sesje PHP

Na szczęście PHP trzyma dane sesji w sensowny sposób — wszystko po stronie serwera, a klient dostaje tylko jednorazowy identyfikator-klucz do tych danych. Klucz jest długi i praktycznie niemożliwy do zgadnięcia.

Przepis:

Jeśli serwer przestanie akceptować daną sesję, to nawet jeśli użytkownik się cofnie i spróbuje wykonać jakieś operacje, to nic nie zdziała — skrypt/PHP odrzuci wylogowaną sesję.