swiatfrontendu.pl
  • arrow-right
  • Kodowaniearrow-right
  • Jak bezpiecznie renderować HTML w React? Uniknij XSS!

Jak bezpiecznie renderować HTML w React? Uniknij XSS!

Olaf Dudek

Olaf Dudek

|

22 września 2025

Jak bezpiecznie renderować HTML w React? Uniknij XSS!

Spis treści

Ten artykuł szczegółowo wyjaśnia, jak bezpiecznie renderować kod HTML przechowywany w zmiennej w aplikacjach React. Dowiesz się, jak używać wbudowanej właściwości `dangerouslySetInnerHTML`, zrozumiesz związane z nią zagrożenia bezpieczeństwa, takie jak ataki XSS, oraz poznasz najlepsze praktyki i alternatywne, bezpieczniejsze rozwiązania.

Jak bezpiecznie renderować HTML ze zmiennej w React kluczowe metody i zagrożenia XSS

  • Do renderowania stringu HTML w React używa się specjalnej właściwości `dangerouslySetInnerHTML`.
  • Standardowe renderowanie w JSX domyślnie "ucieka" znaki HTML, chroniąc przed atakami XSS.
  • Użycie `dangerouslySetInnerHTML` bez odpowiedniej sanityzacji otwiera drogę do ataków Cross-Site Scripting (XSS).
  • Kluczową praktyką bezpieczeństwa jest sanityzacja (oczyszczanie) kodu HTML za pomocą bibliotek takich jak `DOMPurify`.
  • Alternatywne biblioteki, np. `html-react-parser`, konwertują HTML na komponenty React, oferując większą kontrolę i bezpieczeństwo.
  • Metoda `dangerouslySetInnerHTML` jest uzasadniona głównie przy integracji z zaufanymi edytorami WYSIWYG lub systemami CMS.

Czym jest "uciekanie" (escaping) w JSX i dlaczego chroni Twoją aplikację?

Kiedy pracujemy z Reactem i próbujemy wyświetlić zmienną, która zawiera kod HTML, JSX domyślnie stosuje mechanizm "uciekania" (escaping) znaków specjalnych. Oznacza to, że zamiast interpretować tagi takie jak `

` czy `

Problem, który próbujesz rozwiązać: wyświetlanie dynamicznego HTML

Często w aplikacjach webowych stajemy przed wyzwaniem wyświetlenia treści, która jest już sformatowana w HTML. Może to być tekst pobrany z bazy danych, wygenerowany przez edytor WYSIWYG (What You See Is What You Get) w systemie CMS, czy pochodzący z zewnętrznego API. W takich sytuacjach domyślne "uciekanie" znaków przez JSX, choć bezpieczne, staje się przeszkodą. Zamiast pięknie sformatowanego tekstu z nagłówkami, listami i pogrubieniami, użytkownik widzi surowy kod HTML, co jest oczywiście nieakceptowalne z punktu widzenia użyteczności i estetyki. Potrzebujemy więc sposobu, aby React zinterpretował ten HTML jako prawdziwe elementy DOM.

Ataki XSS (Cross-Site Scripting): realne zagrożenie, o którym musisz wiedzieć

Zanim zagłębimy się w techniczne aspekty renderowania HTML, musimy zrozumieć jedno z najpoważniejszych zagrożeń w aplikacjach webowych: ataki Cross-Site Scripting (XSS). Atak XSS polega na wstrzyknięciu złośliwego kodu JavaScript do strony internetowej, który następnie jest wykonywany w przeglądarce niczego niepodejrzewającego użytkownika. Jeśli renderowany HTML pochodzi z niezaufanego źródła na przykład z pola tekstowego, które użytkownik wypełnił na stronie, lub z zewnętrznego API, które może być skompromitowane atakujący może umieścić w nim tag . Co gorsza, może to być znacznie bardziej destrukcyjny kod, który kradnie ciasteczka sesji, przekierowuje użytkowników na złośliwe strony, modyfikuje zawartość strony, a nawet wykonuje żądania w imieniu użytkownika. Jest to główne zagrożenie związane z renderowaniem nieoczyszczonego HTML i dlatego musimy podchodzić do tego tematu z najwyższą ostrożnością.

React dangerouslySetInnerHTML example code

`dangerouslySetInnerHTML`: oficjalne, ale ryzykowne rozwiązanie

Jak poprawnie używać `dangerouslySetInnerHTML`? Składnia i przykłady kodu

React oferuje specjalną właściwość o nazwie dangerouslySetInnerHTML, która pozwala na wstrzyknięcie surowego kodu HTML bezpośrednio do DOM. Jak sama nazwa wskazuje, jest to operacja, która wiąże się z ryzykiem i powinna być używana z rozwagą. Składnia jest specyficzna i wymaga przekazania obiektu z kluczem __html, którego wartością jest nasz string HTML. Poniżej przedstawiam przykład:

import React from 'react'; function MyHtmlComponent({ htmlString }) { return ( 
); } // Przykład użycia: const dynamicHtml = '

Witaj świecie!

To jest dynamiczny HTML.

'; //

Kluczowy obiekt `{ __html: ... }`: Co oznacza i dlaczego jest wymagany?

Obiekt { __html: zmiennaHtml } nie jest przypadkowy. React celowo wymaga tej specyficznej struktury, aby podkreślić "niebezpieczny" charakter operacji. Podwójne podkreślniki (__) w nazwie klucza __html to konwencja w JavaScript oznaczająca, że jest to właściwość wewnętrzna lub specjalna, która nie powinna być używana bez pełnej świadomości konsekwencji. Wymuszając użycie tego obiektu, React zmusza programistę do jawnego potwierdzenia, że rozumie ryzyko związane z wstrzykiwaniem HTML i przyjmuje na siebie odpowiedzialność za zapewnienie bezpieczeństwa renderowanej treści.

Kiedy uzasadnione jest użycie tej metody? Scenariusze z edytorami WYSIWYG i CMS

Mimo swojej nazwy i związanego z nią ryzyka, dangerouslySetInnerHTML ma swoje uzasadnione zastosowania. Oto główne scenariusze, w których możemy rozważyć jej użycie:

  • Integracja z edytorami WYSIWYG: Kiedy Twoja aplikacja integruje się z edytorami tekstu takimi jak CKEditor, TinyMCE czy Quill, które generują i przechowują treść w formacie HTML. W takich przypadkach dangerouslySetInnerHTML jest często najprostszym sposobem na wyświetlenie tej treści.
  • Renderowanie treści z zaufanych systemów CMS: Jeśli pobierasz treść z zaufanego systemu zarządzania treścią (CMS), w którym masz pełną kontrolę nad tym, kto może wprowadzać HTML i wiesz, że jest on bezpieczny, możesz użyć tej metody.
  • Statyczne, kontrolowane treści: W rzadkich przypadkach, gdy renderujesz statyczny HTML, który jest zakodowany na stałe w Twojej aplikacji i nie pochodzi z żadnego zewnętrznego źródła ani od użytkownika.

Nawet w tych scenariuszach, gdzie źródło wydaje się zaufane, zawsze zalecam dodatkowe środki bezpieczeństwa, o których opowiem w kolejnej sekcji.

DOMPurify sanitize example

Bezpieczeństwo przede wszystkim: jak bezpiecznie używać `dangerouslySetInnerHTML`?

Czym jest sanityzacja (oczyszczanie) kodu HTML?

Sanityzacja (oczyszczanie) kodu HTML to proces analizy i modyfikacji ciągu znaków HTML w celu usunięcia lub zneutralizowania wszelkich potencjalnie niebezpiecznych elementów. Polega to na usuwaniu tagów JavaScript (np. ), atrybutów zdarzeń (np. onclick, onerror), niebezpiecznych stylów czy innych elementów, które mogłyby zostać wykorzystane do ataku XSS. Jest to absolutnie kluczowy krok, gdy musisz renderować HTML z niezaufanych źródeł. Bez odpowiedniej sanityzacji, nawet niewielki błąd w logice aplikacji może otworzyć drzwi dla atakujących.

DOMPurify: Twój niezbędny strażnik przed złośliwym kodem

W ekosystemie React i szerzej w świecie JavaScript, biblioteka DOMPurify jest najczęściej rekomendowanym i najbardziej zaufanym narzędziem do sanityzacji HTML. Jest to niezwykle skuteczny i szybki sanitizer, który działa zarówno po stronie klienta, jak i serwera. Jego rola polega na dokładnym parsowaniu kodu HTML i usuwaniu wszystkiego, co może być uznane za złośliwe, pozostawiając tylko bezpieczne i dozwolone elementy. Użycie DOMPurify to de facto standard branżowy w ochronie aplikacji przed atakami XSS podczas renderowania dynamicznego HTML.

Praktyczny przykład: Implementacja `dangerouslySetInnerHTML` z DOMPurify krok po kroku

Pokażę Ci, jak zintegrować DOMPurify z Twoim komponentem React, aby bezpiecznie renderować HTML.

  1. Zainstaluj DOMPurify:

    Najpierw musisz dodać bibliotekę do swojego projektu:

    npm install dompurify
    # lub
    yarn add dompurify
    
  2. Importuj i użyj DOMPurify w komponencie:

    Następnie zaimportuj DOMPurify i użyj funkcji sanitize() przed przekazaniem HTML do dangerouslySetInnerHTML.

    import React from 'react';
    import DOMPurify from 'dompurify'; function SafeHtmlComponent({ htmlString }) { // Sanityzacja HTML przed renderowaniem const cleanHtml = DOMPurify.sanitize(htmlString); return ( 
    ); } // Przykład użycia z potencjalnie niebezpiecznym HTML: const unsafeHtml = `

    Witaj świecie!

    To jest dynamiczny HTML.

    `; // // Output:

    Witaj świecie!

    To jest dynamiczny HTML.

    // Skrypty i atrybuty onerror zostaną usunięte przez DOMPurify.

    Jak widzisz, DOMPurify skutecznie usunął złośliwy kod JavaScript, pozostawiając tylko bezpieczne elementy HTML. To jest właśnie siła sanityzacji!

Najczęstsze błędy podczas sanityzacji i jak ich unikać

Nawet przy użyciu DOMPurify, można popełnić błędy. Oto najczęstsze z nich i wskazówki, jak ich unikać:

  • Zapominanie o sanityzacji: Najprostszy i najgroźniejszy błąd. Zawsze zakładaj, że dane od użytkownika są złośliwe i zawsze je sanityzuj, zanim trafią do dangerouslySetInnerHTML.
  • Sanityzacja po stronie klienta, ale nie po stronie serwera: Idealnie, sanityzacja powinna odbywać się zarówno po stronie serwera (przed zapisaniem do bazy danych), jak i po stronie klienta (przed wyświetleniem). To tworzy podwójną linię obrony.
  • Używanie nieaktualnych lub mniej zaufanych bibliotek: Zawsze wybieraj dobrze utrzymywane i szeroko testowane biblioteki, takie jak DOMPurify. Regularnie aktualizuj zależności.
  • Zbyt liberalne ustawienia sanityzatora: DOMPurify pozwala na konfigurację, które tagi i atrybuty są dozwolone. Jeśli zezwolisz na zbyt wiele (np. na tagi ), osłabisz ochronę. Trzymaj się domyślnych, bezpiecznych ustawień, chyba że masz bardzo konkretny powód, aby je zmienić.
  • Ufanie, że "można to zrobić samemu": Pisanie własnego sanitizera HTML jest niezwykle trudne i obarczone ogromnym ryzykiem. Prawie zawsze skończy się na lukach bezpieczeństwa. Zaufaj sprawdzonym bibliotekom.

html-react-parser vs dangerouslySetInnerHTML comparison

Lepsze i bezpieczniejsze drogi: alternatywy dla `dangerouslySetInnerHTML`

Biblioteka `html-react-parser`: Zamień string HTML na komponenty React

Jedną z popularnych i często bezpieczniejszych alternatyw dla dangerouslySetInnerHTML jest biblioteka html-react-parser. Zamiast wstrzykiwać surowy HTML bezpośrednio do DOM, ta biblioteka parsuje string HTML i konwertuje go na drzewo komponentów React. Oznacza to, że każdy element HTML (np.

, , ) staje się odpowiednim komponentem React, co daje nam znacznie większą kontrolę nad renderowaną treścią.

Jak `html-react-parser` zwiększa bezpieczeństwo i kontrolę?

html-react-parser oferuje kilka kluczowych korzyści w zakresie bezpieczeństwa i kontroli:

  • Kontrola nad elementami: Ponieważ HTML jest konwertowany na komponenty React, możesz przechwytywać i modyfikować poszczególne elementy przed ich renderowaniem. Na przykład, możesz dodać atrybuty rel="noopener noreferrer" do wszystkich linków zewnętrznych lub całkowicie usunąć niechciane tagi.
  • Mniejsze ryzyko XSS (ale nie zerowe): Domyślnie html-react-parser jest bezpieczniejszy niż surowe dangerouslySetInnerHTML, ponieważ nie wykonuje bezpośrednio wstrzykniętego JavaScriptu. Jednakże, nadal istnieje ryzyko wstrzyknięcia złośliwych atrybutów (np. onerror w tagu ), które mogą prowadzić do XSS. Dlatego, nawet przy użyciu html-react-parser, nadal zalecam sanityzację źródłowego HTML za pomocą DOMPurify.
  • Lepsza integracja z ekosystemem React: Renderowanie jako komponenty React pozwala na łatwiejsze stosowanie stylów, obsługę zdarzeń i ogólną spójność z resztą aplikacji React.

Porównanie: `dangerouslySetInnerHTML` vs `html-react-parser` - co wybrać i kiedy?

Aby ułatwić Ci decyzję, przygotowałem tabelę porównawczą obu metod:

Cecha dangerouslySetInnerHTML html-react-parser
Bezpieczeństwo Bardzo niskie bez sanityzacji. Wysokie z DOMPurify. Wyższe niż surowe dangerouslySetInnerHTML, ale nadal zalecana sanityzacja (np. DOMPurify).
Kontrola Brak kontroli nad poszczególnymi elementami po wstrzyknięciu. Wysoka kontrola, możliwość modyfikacji i filtrowania elementów.
Wydajność Potencjalnie minimalnie szybsze (React pomija diffing VDOM dla dzieci). Nieco wolniejsze ze względu na parsowanie i tworzenie komponentów.
Typowe scenariusze Zaufane edytory WYSIWYG, zaufane CMS-y, statyczny HTML. Dynamiczny HTML z różnych źródeł, gdy potrzebna jest kontrola nad elementami, np. modyfikacja linków, dodawanie klas.
Złożoność użycia Prostsza składnia, ale wymaga ręcznej sanityzacji. Wymaga importu i użycia funkcji parsowania, ale oferuje opcje konfiguracji.

Moja rekomendacja jest taka: jeśli potrzebujesz minimalnej ingerencji i masz absolutnie zaufane źródło HTML, możesz użyć dangerouslySetInnerHTML z DOMPurify. Jeśli jednak potrzebujesz większej kontroli nad renderowanymi elementami, chcesz modyfikować ich atrybuty lub masz mniej zaufane źródło, html-react-parser (również z DOMPurify!) będzie lepszym wyborem.

Inne narzędzia warte uwagi: krótki przegląd dodatkowych bibliotek

Oprócz html-react-parser, istnieją inne biblioteki, które oferują podobne funkcjonalności. Warto wspomnieć o react-html-parser, która działa na zbliżonej zasadzie, konwertując HTML na elementy React. Należy jednak zawsze sprawdzić status aktualizacji i utrzymania takiej biblioteki, aby upewnić się, że jest ona bezpieczna i kompatybilna z najnowszymi wersjami Reacta. html-react-parser jest obecnie bardziej aktywna i szerzej rekomendowana.

Dobre praktyki i rekomendacje końcowe

Złota zasada: Nigdy nie ufaj danym od użytkownika

Pozwól, że powtórzę to, co jest fundamentem bezpieczeństwa w każdej aplikacji webowej: nigdy, przenigdy nie ufaj danym pochodzącym od użytkownika ani z niezaufanych źródeł. Każdy string, który może zawierać HTML, a który wpłynął do Twojej aplikacji z zewnątrz, musi zostać poddany rygorystycznej sanityzacji. To nie jest opcja, to jest konieczność. Ignorowanie tej zasady to proszenie się o problemy z bezpieczeństwem, które mogą mieć katastrofalne skutki dla Twoich użytkowników i reputacji aplikacji.

Czy `dangerouslySetInnerHTML` wpływa na wydajność aplikacji i SEO?

Jeśli chodzi o wydajność, użycie dangerouslySetInnerHTML może przynieść niewielki zysk, ponieważ React pomija swój mechanizm porównywania Wirtualnego DOM (diffing) dla dzieci tak wyrenderowanego elementu. Oznacza to, że React nie będzie próbował optymalizować aktualizacji wewnątrz tego bloku HTML. W większości przypadków ta różnica w wydajności jest marginalna i nie powinna być głównym czynnikiem decyzyjnym.

Wpływ na SEO jest bardziej złożony. Treść renderowana za pomocą dangerouslySetInnerHTML jest generalnie indeksowana przez roboty wyszukiwarek. Jednakże, jeśli treść jest ładowana asynchronicznie (np. po zapytaniu do API), jej indeksowanie może być opóźnione lub niepełne, ponieważ roboty mogą nie czekać na pełne załadowanie wszystkich zasobów JavaScript. Aby zapewnić najlepsze SEO dla dynamicznie ładowanej treści, rozważ renderowanie po stronie serwera (SSR) lub generowanie statycznych stron (SSG).

Przeczytaj również: Jak dodać CSS do HTML? Opanuj stylowanie z poradnikiem eksperta

Podsumowanie: Którą metodę wybrać dla Twojego projektu?

Wybór odpowiedniej metody renderowania HTML w React zależy od kilku czynników:

  • Źródło HTML: Czy pochodzi z zaufanego CMS, edytora WYSIWYG, czy od użytkownika?
  • Poziom kontroli: Czy potrzebujesz modyfikować poszczególne elementy HTML?
  • Wymagania bezpieczeństwa: Jak krytyczne jest zapewnienie ochrony przed XSS? (Zawsze krytyczne!)

Moja ostateczna rekomendacja jest jasna: jeśli musisz renderować HTML ze zmiennej w React, zawsze używaj DOMPurify do sanityzacji. Niezależnie od tego, czy zdecydujesz się na dangerouslySetInnerHTML dla prostoty i minimalnego narzutu, czy na html-react-parser dla większej kontroli i elastyczności, sanityzacja jest Twoją pierwszą i najważniejszą linią obrony. Pamiętaj, że bezpieczeństwo nie jest funkcją, którą dodaje się na końcu to fundamentalny aspekt, który należy brać pod uwagę na każdym etapie rozwoju aplikacji.

Źródło:

[1]

https://www.geeksforgeeks.org/reactjs/reactjs-dangerouslysetinnerhtml-attribute/

[2]

https://stackoverflow.com/questions/37337289/react-js-set-innerhtml-vs-dangerouslysetinnerhtml

[3]

https://blog.stackademic.com/ensuring-secure-content-rendering-sanitizing-dangerouslysetinnerhtml-in-react-70f286accaa8

FAQ - Najczęstsze pytania

To właściwość Reacta do wstrzykiwania surowego HTML. Jest "niebezpieczna", bo bez sanityzacji otwiera aplikację na ataki XSS, umożliwiając wykonanie złośliwego kodu JavaScript w przeglądarce użytkownika.

Kluczowa jest sanityzacja (oczyszczanie) HTML przed renderowaniem. Użyj biblioteki DOMPurify, aby usunąć potencjalnie złośliwe tagi i atrybuty, zanim przekazujesz kod do `dangerouslySetInnerHTML`.

Tak, biblioteka `html-react-parser` konwertuje string HTML na komponenty React, oferując większą kontrolę i bezpieczeństwo. Mimo to, nadal zaleca się sanityzację źródłowego HTML za pomocą DOMPurify.

React domyślnie konwertuje znaki specjalne HTML na encje (np. `<` na `<`) w celu ochrony przed atakami XSS. Zapobiega to interpretacji wstrzykniętego kodu HTML jako elementów DOM, wyświetlając go jako zwykły tekst.

Tagi:

jak w react wyrenderować html który jest przechowany w zmiennej
jak wyrenderować html ze zmiennej w react
dangerouslysetinnerhtml bezpieczne użycie

Udostępnij artykuł

Autor Olaf Dudek
Olaf Dudek
Nazywam się Olaf Dudek i od ponad dziesięciu lat zajmuję się analizą oraz pisaniem o technologiach. Moje doświadczenie obejmuje szeroki zakres tematów, od nowoczesnych rozwiązań programistycznych po innowacje w dziedzinie sztucznej inteligencji. Jako doświadczony twórca treści, moim celem jest uproszczenie złożonych danych i dostarczanie obiektywnej analizy, która pozwala czytelnikom lepiej zrozumieć dynamiczny świat technologii. Specjalizuję się w badaniu trendów rynkowych oraz ocenie wpływu nowych technologii na różne branże. Z pasją śledzę najnowsze osiągnięcia i zmiany w tym obszarze, co pozwala mi dostarczać aktualne i rzetelne informacje. Moja misja to zapewnienie czytelnikom źródła wiedzy, które jest nie tylko dokładne, ale także inspirujące i pomocne w podejmowaniu świadomych decyzji w świecie technologii.

Napisz komentarz