03Portfolio
WireMark — bezpieczny język znaczników
Rozszerzony Markdown do bezpiecznego formatowania komentarzy i opisów pisanych przez użytkowników. Biblioteka w TypeScript nie ma zewnętrznych pakietów i przepuszcza tylko to, co jest wprost dozwolone. Ma też integrację z NestJS i edytor wizualny.
W liczbach
- Rodzaje elementów
- 24
- Zewnętrzne pakiety w bibliotece
- 0
- Maksymalna długość tekstu (znaki)
- 100 000
Problem
Komentarze, opisy i posty użytkowników potrzebują czegoś więcej niż zwykły tekst: nagłówków, list, kodu, wyróżnień. Każde takie pole otwiera jednak drogę do ataku XSS, czyli podrzucenia kodu, który wykona się w przeglądarce innych osób: skryptu w treści, linku javascript:, obrazka z doklejonym skryptem albo niewidocznych znaków odwracających kierunek tekstu. Przy filtrowaniu gotowego HTML-a łatwo przeoczyć jeden z tych przypadków.
Podejście
WireMark w ogóle nie przyjmuje HTML-a, więc nie musi go czyścić. Tekst najpierw przechodzi kontrolę: limit 100 000 znaków, ujednolicenie zapisu znaków i usunięcie niewidocznych znaków sterujących. Potem biblioteka rozpoznaje 24 rodzaje elementów i tylko z nich buduje HTML. Znaki specjalne zamienia na bezpieczne odpowiedniki. Linki przechodzą tylko z protokołem https, http albo mailto (opcjonalnie tylko z wybranych domen), obrazki tylko przez https, a kolory, rodzaje ramek, języki kodu i emoji mają własne listy dozwolonych wartości. Obok HTML-a biblioteka zwraca dziennik tego, co odrzuciła, i sygnał, że treść wygląda podejrzanie, a osobna funkcja sprawdza tekst przed zapisem. Do NestJS jest gotowy moduł, który podpina to wszystko w aplikacji.
Efekt
Gotowa jest biblioteka (ok. 970 linii TypeScript, bez zewnętrznych pakietów), integracja z NestJS i dwie strony w czystym HTML i JS. Pierwsza to demo z edytorem i podglądem na żywo, druga to edytor wizualny z menu komend pod „/”, pływającym paskiem formatowania, spisem treści i eksportem do HTML, WireMark albo czystego tekstu. W demo wklejony skrypt, obrazek z doklejonym skryptem i link javascript: wyświetlają się jako zwykły tekst albo są blokowane, a osobny pasek pokazuje, co odrzucono.
Jak to działa
01
Najpierw kontrola, potem formatowanie
Zanim cokolwiek zostanie przetworzone, tekst jest przycinany do limitu długości, ujednolicany i czyszczony z niewidocznych znaków sterujących, bajtów zerowych i mieszanych końców linii.
02
Tylko to, co dozwolone
Link przechodzi tylko z https, http albo mailto (i opcjonalnie tylko z dozwolonej domeny), obrazek tylko przez https. Nieznany kolor odznaki zamienia się w szary, nieznany rodzaj ramki w domyślny, a nazwa języka w bloku kodu zostaje obcięta do liter, cyfr, myślnika i podkreślnika.
03
Wstrzyknięcie zostaje tekstem
Znaki specjalne są zamieniane na bezpieczne odpowiedniki, więc wklejony <script> albo obrazek z doklejonym skryptem wyświetlają się jako zwykły tekst i nic się nie wykonuje. Linki javascript: są odrzucane, a każde takie zdarzenie trafia do dziennika.

04
Rozszerzona składnia
Oprócz zwykłego Markdownu: ramki z uwagami różnego rodzaju, kolorowe odznaki, ukryte spoilery, zaznaczenie, indeks górny i dolny, emoji po nazwie z zamkniętej listy oraz bloki kodu z przyciskiem kopiowania.

05
Gotowe do NestJS
Gotowy moduł do aplikacji w NestJS. Treść wysłana do aplikacji może trafiać do kodu od razu jako bezpieczny HTML, a gdy trzeba, tekst da się też przetworzyć ręcznie.