Aplikacje internetowe

Bełdziowe spojrzenie na aplikacje internetowe

Cross-site request forgery – CSRF

W notce Bezpieczenstwo mechanizmu sesji wspomniałem o niebezpieczeństwie związanym z CSRF. Kilka osób dało mi znać, że pojecie to nadaj nie jest dla nich jasne. W poniższej notce postaram się rozwiązać wszelkie wątpliwości.

Czym jest CSRF?

Atak CSRF polega na wykonaniu akcji, z uprawnieniami innego użytkownika.
Jeśli ta definicja nie jest dla Ciebie jasna poniższy przykład powinien wszystko wyjaśnić:

0. W celu usunięcia swojego konta w serwisie abc.pl należy wywołać skrypt znajdujący się pod adresem abc.pl/usun_konto.
1. Napastnik wysyła do ofiary wiadomość zachęcając ją do kliknięcia w powyższy link.
2. Niczego nieświadoma ofiara klika link co skutkuje usunięciem jej konta.

Innym przykładem ilustrującym problem może być serwis digg.com, który swego czasu był podatny na CSRF. Po wejściu na spreparowaną stronę w ramce otwierana była strona odpowiedzialna za kliknięcie na przycisk Digg, przez co zalogowani użytkownicy nieświadomie wykopywali daną stronę.

Sposób zabezpieczenia

Aby w pełni zabezpieczyć się przed CSRF należy dodać obsługę tokenów do wszystkich ważnych / „inwazyjnych” akcji. Poniżej przykład formularza umożliwiającego zmianę adresu e-mail.

<?
   session_start( );

   if( !$_POST )
   {
      ?>
         <form action="" method="post">
            <p>
               Podaj nowy adres e-mail:
               <input name="email" />
               <input type="hidden" name="token" value="<?= $_SESSION[ 'token' ] = md5( uniqid( rand( ), true ) ) ?>" />
            </p>
            <p>
               <input type="submit" />
            </p>
         </form>
      <?
   }
   else
   {
      if( $_SESSION[ 'token' ] !== $_POST[ 'token' ] )
      {
         die( 'Niepoprawne wykonanie skryptu' );
      }
      
      // dalsze operacje
   }

?>

Jak widać zabezpieczenie polega na wygenerowaniu tokena na stronie prezentującej formularz / link (w przypadku linku należy wygenerowany token dodać jako jeden z parametrów), a następnie zweryfikowanie go podczas przetwarzania wysłanych danych.

Innym sposobem jest podwójne logowanie. Przykład takiego działania możemy zaobserwować w serwisie allegro.pl podczas wejścia na zakładkę Ustawienia w panelu użytkownika, czy tez podczas wejścia do panelu administratora forum phpBB.

One token per session

Generowanie tokena możemy rozwiązać dwojako. Możemy wygenerować jeden token na czas trwania sesji, bądź też generować go przy każdym wywołaniu skryptu. Pierwszy przypadek wydaje się optymalny. Problem pojawi się wtedy, gdy okaże się, że serwis podatny jest na XSS. W takim przypadku napastnik może napisać skrypt, który najpierw odczyta token, a następnie wykona odpowiednia akcje (dla obu token będzie taki sam).


Tagi: , , , ,
Kategoria: Bezpieczeństwo, HTML Injection


11 komentarzy

  1. Bardzo przydatny tekst. Dzieki i prosze o wiecej :)

  2. Dla uzupełnienia – jednorazowe tokeny dla formularzy też nie zapobiegają wykorzystaniu CSRFa XSSem. Wystarczy wstawić XSSem ukryty iframe ze stroną formularza (opcjonalnie security=restricted żeby wyłączyć framekillera) i po sprawie ;)

  3. kogo ja tu widze :-) prawda ze nie zabezpieczaja, ale minimalizuja ryzyko, bo zeby ominac jednorazowego tokena XSS musialby byc na tej samej stronie co formularz :)

  4. mozna jeszcze inaczej zrobic :)

    token generujemy na podstawie danych zwiazanych z userem np md5( login + czas ) i w sesji zamiast zapisywac token zapisujemy sam czas; po submicie ponownie generujemy token i spr czy jest taki sam jak przeslany; nawet jesli ktos ukradnie token to nic mu nie da bo md5( login_ofiary + czas ) != md5( login_atakujacego + czas )

    :)

  5. Przeciez po wykonaniu submitu minie jakis czas i wtedy md5(login + time()) juz nie bedzie rowny poprzedniemu.

  6. „i w sesji zamiast zapisywac token zapisujemy sam czas;”

    tak więc problem znika :-)

  7. Najważniejsze, aby wszystkie akcje wywoływać metodą POST. Jeżeli usuwamy konta metodą GET, wystarczy umieścić obrazek prowadzący do /delete/xxx na dowolnym forum. Czy token w formularzu jest lekarstwem na wszystkie zagrożenia? Na złośliwej stronie można go wykraść. Ładujemy stronę do ukrytej ramki i… nawet nie trzeba wyciągać żadnych wartości. Przechwytujemy formularz i wywołujemy submit(). Czy są lepsze zabezpieczenia? Potwierdzanie hasła może być dobrą formą weryfikacji, ale tylko na właściwej stronie (oszust wykorzysta rozciągniętą ramkę na 100% i wykradnie cenne informacje, zanim formularz zostanie wysłany)!

  8. token jest jednorazowy, tzn za kazdym razem inny tak wiec nawet jak go wykradniesz to nic Ci nie da

  9. Ta notka z pewnością rozwiała wszelkie wątpliwości. Pzdr :)

  10. Kshyhoo napisał(a):

    A jak to się ma do formularzy w wielu krokach? Wypadało by generować token w każdym kroku…

  11. no tak :-) token generowany jest za każdym razem jak tworzony jest formularz

Dodaj komentarz