Jeszcze kilka dni temu pisałem o atrybucie httpOnly dla ciasteczek, dzięki któremu częściowo (minimalnie) możemy się zabezpieczyć przed atakami typu XSS, czyli przed wstrzykiwaniem niebezpiecznego kodu do naszej strony.
Dzisiaj uderzymy w temat z nieco innej strony, mowa bowiem o filtrowaniu danych wchodzących do aplikacji przy pomocy świetniej biblioteki, HTML Purifier.
Czym jest HTML Purifier?
Jest to biblioteka, która oczyszcza kod HTML ze wszelkich brudów – niedozwolonych przez programistę czy niezgodnych ze specyfikacją W3C elementów i atrybutów HTML. Ponadto biblioteka ta pozwala na definiowanie własnych filtrów, co czyni ją bardzo rozszerzalną.
Przykładowo: mamy formularz WYSIWYG na komentarze od użytkownika. Użytkownik tworzy swój kod HTML, dodając tabelki, obrazki, filmiki z YouTube, etc. Kod taki następnie trafia pod HTML Purifier, w którym możemy wywalić tabelki, a dodatkowo utworzyć filtr, który pobierze wszystkie obrazki na nasz serwer i jednocześnie podmieni adresy URL obrazków na nowe.
Wszystko to w kilkunastu linijkach kodu – nie musimy się także martwić nieprawidłowym kodem HTML czy próbą przeprowadzenia ataku XSS – HTML Purifier zajmie się tym za nas.
Przykładowe użycie
HTML Purifier można konfigurować na wiele różnych sposobów – możliwości konfiguracyjnych jest naprawdę wiele.
W większości przypadków wystarczy jednak domyślna konfiguracja, którą sam najczęściej też wykorzystuję w swoich projektach, tzn. :
1 2 3 4 5 6 | $config = HTMLPurifier_Config::createDefault(); $config->set('Attr', 'EnableID', true); $purifier = new HTMLPurifier($config); $html_code = $purifier->purify($html_code); |
Nie wiem dlaczego w domyślnym ustawieniu usuwany jest atrybut ID z elementów HTML, niemniej powyższe ustawienia przywraca możliwość stosowania identyfikatorów.
Oczywiście mamy mnóstwo innych opcji konfiguracyjnych. Możemy oczyszczać kod wyjściowy (Tidy HTML w trzech poziomach: light, medium oraz heavy):
1 | $config->set('HTML.TidyLevel', 'heavy'); |
ustawiać odpowiedni element Doctype dokumentu HTML i formatować dokument zgodnie z jego założeniami:
1 | $config->set('HTML.Doctype', 'XHTML 1.0 Strict'); |
czy też definiować atrybuty i ich dopuszczalne właściwości.
Jak widać, możliwości jest wiele, a to tylko niewielki ułamek tego co potrafi ten kombajn. Więcej możemy odnaleźć w dokumentacji, stworzonej zarówno dla użytkownika, jak i dla robotów lubiących czytać dokumentację wygenerowaną przez Doxygen-a :D
Warto też zapoznać się z dokumentem prezentującym skuteczność biblioteki w obronie przeciwko atakom typu XSS: HTML Purifier XSS Attacks Smoketest.
Podsumowanie
HTML Purifier zapewnia wsparcie dla UTF-8, a nawet HTML5. Kod źródłowy jest otwarty dla każdego developera (rozprowadzany na licencji LGPL), biblioteka jest wciąż rozwijana, zapewnia wsparcie dla CSS i długo jeszcze można by wypisywać kolejne zalety.
A wady? Jak na razie nie udało mi się ich znaleźć. Czasem uciążliwe bywa dodawanie obsługi niestandardowych atrybutów HTML. Ponadto taki kombajn zużywa sporo pamięci procesora, niemniej ilekroć przepuszczamy HTML przez takie narzędzie? W moim przypadku bywa to nieczęsto – a jeśli często to korzystam z buforowania i problem rozwiązany.
I na sam koniec warto wspomnieć, że z biblioteki korzysta też wielu dobrych graczy, np. :
Stanowi to solidne potwierdzenie tego, iż biblioteka HTML Purifier jest naprawdę warta uwagi.
Jako lepszy kolega biblioteki Tidy w PHP, na pewno zostanie przeze mnie wypróbowany. Dzięki za informacje!
IDki są domyślnie wyłączane przez HTMLPurifiera prawdopodobnie dlatego, że w przypadku zagnieżdżenia strony w można je wykorzystać do wyciągnięcia informacji z atakowanej strony.
Działa to tak:
[iframe src=http://atakowana-strona.pl#jakis_konkretny_id]
i potem przez wlasciwosc scrollTop na objekcie iframe zczytujesz, czy taki idik wystepuje na stronie (scrollTop > 0) czy nie ( = 0). Atak niby wydumany, ale swego czasu udalo sie zaatakowac jakis system webmailowy i sprawdzic liste maili na okreslone tematy u ofiary.
Szczegóły są tutaj: http://www.contextis.co.uk/resources/white-papers/clickjacking/Context-Clickjacking_white_paper.pdf
Ale, umówmy się, ryzyko takiego ataku jest dość małe, więc to raczej „puryzm” autora HTMLPurifiera.
Z dobrych filtrów przeciwXSSowych warty uwagi jest jeszcze Wibble – powinien być o wiele szybszy od purifiera.
Atrybut ID jest usuwany, żeby „wesoły hateemelowiec” nie duplikował ID już istniejących (#header) i nie zburzył działania aplikacji korzystającej z odwołań do DOM po ID.
@Krzysztof: faktycznie, dość oryginalny sposób ataku i wcześniej się z tym nie spotkałem, więc i sam nie wpadłbym na taki pomysł.
Pokrewnych dla HTML Purifiera jest kilka, m. in. wspomniany przez Ciebie Wibble czy htmLawed. Opisałem jedynie HTML Purifier, bo tylko z nim mam praktyczne doświadczenie :-) I w sumie wystarczy, choć warto też znać konkurencję.
@Marcin: masz rację – na stronie może być tylko jeden element o danym identyfikatorze i użytkownik mógłby wprowadzić bałagan dublując ID, nie pomyślałem o tym. U siebie potrzebowałem dopuścić atrybut ID, aby w panelu administracyjnym uprawnione osoby mógły zmieniać zawartość boxów dodając identyfikatory elementów, a następnie za pomocą CSS czy JavaScript dodawać konkretne zachowania/wygląd.
@Marcin
No tak, to trochę prostsze wytłumaczenie ;) Z tego, co teraz czytam, autorzy dodają też, że dublujące się id psują też walidację (a im na niej b. zależy).
HTML Purifier jest jednym z lepszych rozwiązań, które znam oferujące pełne filtrowanie i nie tylko
Swego czasu miałem do czynienia również z ksesem. Jednak HTML Purifier bije go na głowę.
Jego wadą jest fakt, że czasami potrafi zająć całą dozwoloną pamięć i wywalić php’a. Jednak są to przypadki sporadyczne i dzieją się tylko dla bardzo rozbudowanego html’a (na przykład co poniektórych mailingów htmlowych), aczkolwiek warto mieć ten fakt na uwadze.