Aplikacje internetowe

Bełdziowe spojrzenie na aplikacje internetowe

Kontrola długości danych

Czy podczas pobierania danych od użytkowników, które następnie przesyłane są do bazy kontrolujecie ich długość? Generalnie jeśli nie operujemy na wrażliwych danych operacje tą można pominąć. Podczas zapisu zbyt dużej porcji danych SZBD usunie jej nadmiar i ukończy operacje z powodzeniem nie generując żadnego błędu. Jednak czy na pewno kwestia kontroli długości danych jest błahą sprawą? Jak pokazuje przypadek WordPress’a nie.

Brak kontroli długości wprowadzanych danych doprowadził do możliwości zresetowania hasła dowolnego użytkownika, a co za tym idzie przejęcia jego konta. Poniżej przykładowy scenariusz ataku wykorzystującego ten błąd.

Akcja

Po pierwsze musimy znać login użytkownika, którego konto chcemy przejąc. Podczas instalacji WordPress’a tworzone jest domyślne konto administratora o loginie „admin”, co więcej zmiana owego loginu, nie jest możliwa spod panelu administratora. Jest to duży błąd ponieważ potencjalny napastnik od razu wie jakim loginem posługuje się administrator.

Kiedy posiadamy już nazwę użytkownika wystarczy tylko założyć konto o takim samym loginie i skorzystać z opcji przypominania hasła. Może się wydawać, że operacja ta jest niemożliwa do wykonania, ponieważ przed dodaniem nowego użytkownika sprawdzane jest czy podany login jest wolny. Nic bardziej mylnego.

Z zasady sprawdzanie czy podany login jest wolny odbywa się w następujący sposób:

SELECT id
FROM users 
WHERE login = "admin";

Jeśli zapytanie zwróci jakieś rekordy oznacza, to że podany login jest już zajęty i należy wygenerować odpowiedni błąd. Co się jednak stanie jeśli jako login podamy nie „admin”, a
„admin            123”? Podany login nie zostanie znaleziony w bazie, a co za tym idzie konto zostanie pomyślnie założone.

Teraz tylko pojawia się pytanie co ma „admin” do „admin            123” w końcu są to dwa różne konta. Są różne, ale tylko tak długo jak nie bierzemy pod uwagę długości pola, w którym przechowywany jest login. Jeśli założymy, że długość pola to 8 znaków, nasz login zmieni postać z „admin            123” na „admin   ”. Jak można zauważyć jedyna różnica jaka pozostała pomiędzy naszym loginem, a loginem „admin” to kilka spacji. I tu z pomocą przychodzi nam jedna z właściwości mySQL. Podczas zapisywania danych usuwa on wszystkie spacja z początku oraz końca ciągu. Dzięki temu uzyskujemy taki sam login jaki posiada administrator.

W celu lepszego zrozumienia powyższego opisu kawałek kodu, który zademonstruje problem.

$login = 'admin            123';
	
// sprawdzenie czy login jest wolny
$query = mysql_query( '	SELECT id 
			FROM users
			WHERE login = "' . $login . '";' );
$query = mysql_fetch_object( $query );

// jeśli zapytanie nie zwróciło wyniku login jest wolny
// i można utworzyć konto
if( !$query )
{
	mysql_query( '	INSERT INTO users( login )
			VALUES( "' . $login . '" )' );
	// login został przycięty zgodnie z długością pola oraz zostały
	// usunięte spacje; dzięki temu $login  == 'admin'
}

Wykonanie powyższego kodu skutkuje pojawieniem się w bazie drugiego konta o loginie „admin”.

Obrona

Tak samo jak w większości przypadków tak i z tym problemem można sobie łatwo poradzić. Najprostszym sposobem jest kontrola rozmiaru przesyłanych danych, tak aby zgadzał się on z rozmiarem pola w bazie.

Istnieje jeszcze drugi sposób zabezpieczenia związany z projektowaniem bazy. Mianowicie należy nałożyć na pole „login” indeks UNIQUE. Dzięki temu będziemy mieli pewność, że każdy login w bazie będzie unikalny, a próba dodania istniejącego loginu zakończy się błędem.


Tagi: ,
Kategoria: Bezpieczeństwo, Bazy danych


9 komentarzy

  1. bardzo ciekawy artykuł, napisz może przykładowe rozwiązanie (kod) :) albo najlepiej całościowo zoptymalizuj wp i udostępnij WordPress 2.6 PL by Bełdzio :D

  2. Generalnie to nie ma co pisać :-) Dodajesz index UNIQUE na odpowiednie pole + korzystając ze strlen( ) dla PHP sprawdzasz długość danych :-)

  3. Bełdzio jak zawsze ciekawy wpis :) Sam padłem ofiarą tego błędu na zapomnianym WP.

  4. A która baza danych tak robi? to nie najlepsze rozwiązanie, powinna nie pozwolić na umieszczenie rekordu…

    Tomasz Bartczak
    Racjonalny Developer

  5. biorąc pod uwagę, że WordPress działa na mySQL? :)) jak się dobrze skonfiguruje baze to nie będzie pozwalała na takie rzeczy

  6. Co do strlen, to jest szybszy sposób na sprawdzenie czy dany string nie jest za długi.
    Załóżmy, że maksymalna dozwolona długość to 8, wówczas piszemy cos takiego:
    if(isset($string{8})) //tu obsługa błędu

    Ogólnie stringa możemy traktowac jak tablice, tylko zamiast nawiasów kwadratowych używamy klamer. Isset natomiast jest dużo szybsze od strlen.

    Ot taka drobna optymalizacja :)

  7. Jak najbardziej można tak zrobić, aczkolwiek nie jestem pewien czy w nowszych wydaniach PHP takie traktowanie stringów nie zostało / zostanie usunięte.

  8. Na stronie manuala nic na ten temat nie piszą, więc raczej od tego nie odejdą w najbliższej przyszłości. W każdym razie php 5.4 jeszcze to obsługuje :)

    btw. doczytałem, że kwadratowych nawiasów też można użyć

  9. W takim razie moje niedopatrzenie :)

Dodaj komentarz