Oczyszczanie danych HTML na wejściu i wyjściu

07 marca 2016
1 gwiadka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek

Do prostego oczyszczania danych HTML można używać funkcji htmlentities(). Jeśli natomiast potrzebne jest bardziej zaawansowane rozwiązanie, lepszym rozwiązaniem jest skorzystanie z biblioteki HTML Purifier.

Rozwiązanie przetestowano przy użyciu biblioteki HTML Purifier 4.6.0.

Jeśli aplikacja wyświetla na stronie dane wprowadzone do niej przez użytkownika, to musi je najpierw „oczyścić”, aby pozbyć się potencjalnie groźnego kodu HTML. Nieżyczliwy nam użytkownik może tak spreparować znaczniki HTML, aby użyte na stronie stanowiły zagrożenie dla jej użytkownika.

Nawet jeśli poczujesz pokusę, aby do oczyszczania danych HTML wykorzystać wyrażenia regularne, koniecznie się jej oprzyj. HTML to skomplikowany język i możesz mieć pewność, że każda samodzielna próba oczyszczania danych w tym formacie zakończy się porażką.

Niektórzy radzą też używać funkcji strip_tags(). Pod względem technicznym jest ona całkiem bezpieczna, ale jest to też bardzo „durna” funkcja, tzn. jeśli zostanie do niej przekazany nieprawidłowy kod HTML (np. z brakiem znacznika zamykającego), to może usunąć o wiele więcej niż byśmy chcieli. Zatem wybór funkcji strip_tags() nie jest najlepszy, ponieważ użytkownicy nie mający wiedzy technicznej często używają znaków < i > w swoich pisemnych wypowiedziach.

Jeśli ktoś przeczytał artykuł o sprawdzaniu poprawności adresów e-mail w PHP, to może rozważać też możliwość użycia funkcji filter_var(). Niestety funkcja filter_var() ma problemy ze złamaniami wiersza i wymaga trudnej konfiguracji, jeśli ma działać podobnie do funkcji htmlentities(). Dlatego jej wybór też nie jest najlepszym pomysłem.

Oczyszczanie danych w prostych przypadkach

Jeżeli aplikacja internetowa ma za zadanie tylko zastąpić wszystkie elementy składni HTML encjami (i w ten sposób je unieszkodliwić, ale pozostawić je w kodzie), należy posłużyć się funkcją wbudowaną htmlentities(). Funkcja ta jest znacznie szybsza od biblioteki HTML Purifier, ponieważ nie sprawdza poprawności kodu HTML, a jedynie go unieszkodliwia.

Funkcja htmlentities() różni się od swojej kuzynki htmlspecialchars() tym, że stosuje kompleksowo encje HTML, a nie tylko ich niewielki podzbiór.

Przykład

	<?php
// O nie!  Użytkownik wysłał w formularzu szkodliwy kod HTML, a my musimy go przedstawić na stronie internetowej!
$evilHtml = '<div onclick="xss();">Mua-ha-ha! Podkręcam mój złowieszczy wąs...</div>';
 
// Dodajemy znacznik ENT_QUOTES, aby zamieniać na encje zarówno pojedyncze jak i podwójne cudzysłowy.
// Stosujemy kodowanie znaków UTF-8, jeśli zapisaliśmy tekst w tym formacie  (tak jak powinniśmy).
// Więcej informacji na ten temat znajduje się w artykule o UTF-8 i PHP.
$safeHtml = htmlentities($evilHtml, ENT_QUOTES, 'UTF-8'); // Teraz zmienna $safeHtml zawiera unieszkodliwiony kod HTML. Jej zawartość można bez obaw przedstawić użytkownikom!
?>

Oczyszczanie danych w złożonych przypadkach

W wielu aplikacjach internetowych takie proste rozwiązanie, jak przedstawione powyżej jest niewystarczające. Często programista chce usunąć cały kod HTML albo przepuścić tylko niewielki zestaw elementów tego języka. Do takich celów doskonale nadaje się biblioteka HTML Purifier.

HTML Purifier to gruntownie przetestowana, ale powolna biblioteka, więc jeśli nie ma się zbyt wygórowanych wymagań, lepiej zamiast niej używać funkcji htmlentities().

Zaletą biblioteki HTML Purifier w porównaniu z funkcją strip_tags() jest to, że sprawdza poprawność kodu przed jego unieszkodliwieniem. Dzięki temu, jeśli użytkownik wpisze nieprawidłowy kod HTML, biblioteka HTML Purifier daje większą szansę na zachowanie jego znaczenia niż funkcja strip_tags(). Poza tym biblioteka ta ma wiele opcji konfiguracyjnych, za pomocą których można wskazać, które elementy HTML mają być przepuszczane przez filtr.

Wadami biblioteki HTML Purifier są jej powolność, konieczność dokonania pewnych ustawień konfiguracyjnych, co może być niemożliwe w hostingach współdzielonych oraz skomplikowana i niejasna dokumentacja. Poniżej znajduje się przykład podstawowej konfiguracji. Jeśli chcesz poznać bardziej zaawansowane funkcje tej biblioteki, zajrzyj do jej dokumentacji.

Przykład

	<?php
// dołączenie do skryptu biblioteki HTML Purifier
require_once('htmlpurifier-4.6.0/HTMLPurifier.auto.php');
 
// O nie!  Użytkownik wysłał w formularzu szkodliwy kod HTML, a my musimy go przedstawić na stronie internetowej!
$evilHtml = '<div onclick="xss();">Mua-ha-ha! Podkręcam mój złowieszczy wąs...</div>';
 
// Utworzenie obiektu HTML Purifier o domyślnych ustawieniach.
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
 
$safeHtml = $purifier->purify($evilHtml); // Teraz zmienna $safeHtml zawiera unieszkodliwiony kod HTML. Jej zawartość można bez obaw przedstawić użytkownikom!
?>

Pułapki

  • Jeśli funkcja htmlentities() zostanie użyta z niewłaściwym kodowaniem znaków, można otrzymać zaskakujące wyniki. Dlatego wywołując tę funkcję zawsze określaj kodowanie znaków, które powinno zgadzać się z kodowaniem oczyszczanego łańcucha. Więcej szczegółów na ten temat znajduje się w artykule o UTF-8 i PHP.
  • W wywołaniu funkcji htmlentities() zawsze podawaj parametry ENT_QUOTES i kodowania znaków. Domyślnie funkcja ta nie koduje pojedynczych cudzysłowów. Co za głupota!
  • Biblioteka HTML Purifier bardzo powoli przetwarza skomplikowane dokumenty HTML. Dlatego zwrócone przez nią wyniki oczyszczania dobrze jest zapisywać w buforze, np. APC.

Autor: Alex Cabal

Źródło: http://phpbestpractices.org/

Tłumaczenie: Łukasz Piwko

Treść tej strony dostępna jest na zasadach licencji CC BY-SA 3.0

Zobacz również:

Dyskusja

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *