Aplikacje internetowe

Bełdziowe spojrzenie na aplikacje internetowe

mod_rewrite jako pierwsza linia obrony przed wstrzyknięciami

Czym jest mod_rewrite?

mod_rewrite jest modułem serwera Apache, przeznaczonym do przepisywania adresów URL. Wykorzystując jego możliwości możemy sprawić by adresy podstron naszego serwisu były bardziej naturalne dla jego użytkowników. Aby skorzystać z jego możliwości należy utworzyć plik „.htaccess” i w nim umieścić reguły przepisywania.


Przykład działania mod_rewrite:

Adres widziany przez użytkowników:
http://www.sklep.pl/produkty/szafa.html

Adres widziany przez serwer:
http://www.sklep.pl/produkty.php?produkt=szafa

Przepisywanie adresów vs wstrzyknięcia

Błędna filtracja danych pochodzących od użytkowników może doprowadzić do modyfikacji kodu strony bądź zapytań skierowanych do bazy danych. W obu przypadkach bezpieczeństwo strony zostaje zagrożone umożliwiając dostęp agresorowi do wrażliwych danych.

Aby agresor mógł wstrzyknąć niebezpieczny kod we wnętrze naszego systemu musi posłużyć się znakami specjalnymi (np. < / > dla ataku XSS, bądź ‚ / = dla SQL Injection). Wywnioskować z tego możemy, że jedynymi znakami względnie bezpiecznymi dla nas są cyfry oraz litery.

Tak więc jeśli mielibyśmy możliwość określenia zakresu znaków wysyłanych przez użytkowników moglibyśmy zwiększyć bezpieczeństwo naszego serwisu. I tu z pomocą przychodzi mod_rewrite.

Case study

Opis

Programista tworzący sklep internetowy spostrzegł, że jego kod podatny jest na atak typu SQL Injection. Mianowicie zmienna „ID” przesyłana wraz z adresem strony trafia do zapytania SQL bez uprzedniej filtracji. Umożliwia to poszerzenie oryginalnego zapytania o kod agresora. Jako, że każda kategoria w sklepie reprezentowana jest przez osobny plik, a kategorii jest tak wiele, że programista nawet nie myśli o ręcznej modyfikacji każdego pliku tworzy regułkę mod_rewrite, która ma uchronić serwis przed wykorzystywaniem słabości zmiennej „ID”.

Rozwiązanie

Kod PHP:

<?php
	mysql_connect( 'host', 'user', 'passwd' )
		or die( 'Nie udalo sie palczyc z baza danych.' );

	mysql_select_db( 'db' )
		or die( 'Nie udalo wybrac sie bazy.' );

	$query = mysql_query( 'SELECT * FROM produkty WHERE id = ' .  $_GET['id'] )
		or die( 'Nie udalo sie wykonac zapytania.' );

	while( $row = mysql_fetch_row( $query ) )
	{
		/*
			Prezentacja wyników
		*/
	}
?>

Regułki mod_rewrite:

RewriteEngine on

RewriteCond %{QUERY_STRING} (id=d$)|(id=(d?)&)|^$ [NC]
	RewriteRule .* - [L]

RewriteRule .* - [F,L]

Opis rozwiązania

Zadaniem powyższych reguł jest sprawdzenie czy wartość parametru „ID” składa się wyłącznie z cyfr. Jeżeli reguła nie zostanie spełniona zamiast strony produktu wyświetli się strona z błędem 301 czyli brak dostępu do strony.

Przedstawiona reguła pozwala ochronić nasz system w czasie opracowywania bezpieczniejszej wersji skryptu.

Update

Wczorajszego wieczora Łukasz Pilorz poinformował mnie, że powyższa regułka mod_rewrite nie działa. Problemem okazała się rozbieżność w wersjach serwera Apache. Dopiero linia 2.x obsługuje w pełni wyrażenia regularne PERLa, z których skorzystałem pisząc regułkę (d). Aby rewrite zadziałał bez względu na wersję Apache trzeba go zmodyfikować do następującej formy:

RewriteEngine on

RewriteCond %{QUERY_STRING} (id=[0-9] $)|(id=(([0-9] )?)&)|^$ [NC]
	RewriteRule .* - [L]

RewriteRule .* - [F,L]

czyli zamienić d na [0-9]

Warto zajrzeć


Tagi: ,
Kategoria: Bezpieczeństwo, Apache


8 komentarzy

  1. ConSi napisał(a):

    Teraz jeszcze napisz co zrobic gdy nie ma .htaccess obslugi albo mod_rewrite ukradli ;}

  2. Bełdzio napisał(a):

    Wtedy zostaje edycja plików i dodanie filtrów :-)

  3. Chyba jednak zdecydowana większość programistów zabezpieczenia zawarłaby jż w kodzie…
    Ale w sumie spojrzenie na temat ciekawe, takie „z innej strony”

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

    Sposób ten powstał pod podane case study, gdyż jest ono prawdziwe. Miał on zabezpieczyć sklep w czasie wdrażania nowego systemu. Tak więc jest on nie tyle zabezpieczeniem samym w sobie, ale sposobem ochrony podczas wdrażania nowego kodu.

  5. sopel napisał(a):

    ok, ale przemilczana jest wydajność takiego rozwiązania. mielenie przez apache przy kazdym żądaniu wyrazeń regularnych moze czasem dac znaczący narzut. z drugej strony nie jest to żadna nowość, większe bezpieczeństwo często osiąga się kosztem wydajności – problem jak to wypśrodkować…

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

    Oczywiście, przy większym ruchu może to troszkę przymulić serwer, lecz użycie rewrita ma na celu zyskanie na czasie, który zostanie poświęcony na łatanie kodu, tak więc przez te kilka dni może Apache troche poprawcować ;-)

  7. Mysza napisał(a):

    A nie lepiej po prostu filtrować za pomocą php ?
    $get = (int)$_GET[‚zmienna’];
    tzw. rzutowanie.
    jeśli zmienna nie jest liczbą => skrypt się nie wykona.

    Post stary, ale może się komuś przyda :)

  8. Zdecydowanie lepiej. Problem polegał na tym, że zgodnie z case study nie było możliwości edycji plików PHP – a dokładniej była, ale trzeba było wprowadzić szybką łatę, które usunie błąd na czas załatania kodu PHP.

Dodaj komentarz