W zasadzie kiedy muszę koniecznie sanitizować stringi przed przesłaniem ich klientowi, by zapobiec XSS?

0

Pamiętam, że mi tłuczono, że niezaufane stringi (czyli wszystkie przesyłane od userów do serwera) muszą koniecznie być walidowane i sanityzowane przed przesłaniem ich innym userom. Tyle, że jakoś tego nie widzę...

No mam sobie czata w tej grze. Kod po stronie klienta jest mniej więcej taki:

let p = document.createTextNode('p')
p.appendChild(document.createTextNode(message))
document.getElementById('chatbox').appendChild(p)

Gdzie message to wiadomość, którą jeden z userów wysyła na czata, i którą serwer rozgłasza wszystkim klientom.

No to się zacząłem bawić. Mianowicie (bez implementowania po stronie serwera żadnej walidacji) wysłałem sobie na czata wiadomość treści następującej:

<script>window.alert("injection")</script>

I... nic. Wyświetla się na czacie normalnie. Żadnego wyskakującego okienka.

No to teraz implementuję po stronie serwera zamianę < na &lt; Wysyłam tą samą wiadomość. Oto, co wyświetla się na czacie:

&lt;script>window.alert("injection")&lt;/script>

Wnoszę zatem, że document.createTextNode(whatever) po stronie klienta jest odporny na wszelkie dziwne pomysły i jego użycie już starczy za wszelkie walidacje, sanityzacje, i inne takie? Tak, że na własną rękę żadne walidacje już nawet nie powinny być robione? Czy jednak trzeba jeszcze czegoś dopatrzeć?

Jakaś zasada, kiedy należy próbować sanityzować niezaufane stringi (jak mnie uczono), a kiedy nie należy?

0

Zawsze trzeba. Nigdy nie ufaj userowi. to, że ten sposób ci przeszedł nie znaczy, że nie ma 20 innych sposób, np poprzez zabawę z kodami unicode.

0

@mr_jaro:

No fajnie, ale jak pisałem, próba walidacji skończyła się tym, że mi się string źle wyświetlał. User musi być w stanie na czat wysłać znak <, nie mogę wymusić, by każdy znak < się wyświetlał jak &lt; W takim razie jak mam walidować, żeby robić to poprawnie? I blokować zabawy z kodami unicode?

EDIT:

jak pisałem, próba walidacji skończyła się tym, że mi się string źle wyświetlał

Tzn. jak wydawało mi się, że pisałem. Poprawiłem OP.

EDIT 2: Jejku, naprawdę są problemy z tymi encjami. Poprawiłem ten post.

0

dlaczego? czemu ni może zmienić m.in znaków <>? dopuszczasz by ludzie wysyłali html? podaj stronę to będę wiedział gdzie zacząć psocić.

0

czemu ni może zmienić m.in znaków <>?

Nie chodzi mi o HTML. Chodzi mi o to, że te znaki są również używane jako znaki większości / mniejszości. Jako że mają one liczne "grzeczne" zastosowania, nie tylko do różnych XSSów, to nie sądzę, by zakazanie tych znaków albo zamienianie wszystkich ich wystąpień na krzaczki było dobrym... user experience.

Skądinąd, przecież zamiana tych znaczków na krzaczki nie rozwiąże problemu wspomnianych przez Cb zabaw z Unicodem, toteż wnoszę, że oprócz tego jeszcze coś innego jest wymagane?

podaj stronę to będę wiedział gdzie zacząć psocić.

Może jak 2 miesiące poczekasz jeszcze, to będę miał się czym pochwalić, na razie gry jeszcze nie opublikowałem :)

Ale jak pamiętam rozmaite webowe gry zawierjające czaty, to nie zabraniały one przesyłania na czata < i >. Ot przykład z Pokemonów: ktoś napisał, że "clefable > wigglytuff" (co miało znaczyć, że clefable jest lepszy niż wigglytuff i należy w drużynie wyrzucić wigglytuffa i wstawić clefable) Nie chciałbym blokować podobnych zastosowań.

Wydaje mi się, że celem jest nie zabronienie tych znaków, tylko wymuszenie, by zawsze wyświetlały się one jedynie jako tekst, a nie miały żadnych dziwnych skutków ubocznych?

1
kmph napisał(a):

Jakaś zasada, kiedy należy próbować sanitizować niezaufane stringi (jak mnie uczono), a kiedy nie należy?

Jeśli już musisz użyć tej słownej osobliwości to sanityzować..

0

Wiesz, skąd mamy wiedzieć jak napisany jest twój chat i dlaczego & lt; wyświetla się jako & lt;, a nie <? :P

Generalnie, to ktoś wysyła Ci np.

123 < 234, który jest zamieniany na 123 & lt; 234 i wyświetlany u usera jako 123 < 234 ale "interpretowany" jako 123 & lt; 234 aby nie ingerować w strukturę znaczników.

Dodałem spację pomiędzy & i lt bo post się trochę bugował.

https://jsfiddle.net/usofdcvw/

https://jsfiddle.net/amzLkhru/

0

wstaw sobie na czysto znak < i zobacz, w podglądzie kodu jak ładnie przeglądarka ci zaznacza, niepoprawne użycia znaku. Zrób np coś takiego 1 < 10, 10 > 1 a dostaniesz informacje "niepoprawny znacznik początkowy <10, 10>" dlatego, że każdy czysty znak <> jest odbierano jako html

0

Najprawdopodobniej ten twój skrypt zamienia każde & na &amp;
W efekcie podwójnie zaencjowane < przyjmuje w kodzie postać &amp;lt; i przestaje się wyświetlać jako <.

Możesz to obejść np. zamieniając najpierw < na jakiś_unikalny_ciąg_znaków,
pozwolić skryptowi zaencjować &,
zamienić unikalny_unikalny_ciąg_znaków na &lt;.

0
WeiXiao napisał(a):

Wiesz, skąd mamy wiedzieć jak napisany jest twój chat i dlaczego & lt; wyświetla się jako & lt;, a nie <? :P

Ponieważ wstawienie stringa zawierającego &lt; za pomocą document.createTextNode() wyświetla się jako &lt;, a nie jako <. Podczas gdy wstawienie tego samego stringa za pomocą innerHTML wyświetla się jako <. Ja zaś użyłem createTextNode().

WeiXiao napisał(a):

Generalnie, to ktoś wysyła Ci np.

123 < 234, który jest zamieniany na 123 & lt; 234 i wyświetlany u usera jako 123 < 234 ale "interpretowany" jako 123 & lt; 234 aby nie ingerować w strukturę znaczników.

Jednakże zastosowanie tej metody w połączeniu z document.createTextNode() da efekty dalekie od optymalnych.

WeiXiao napisał(a):

https://jsfiddle.net/usofdcvw/

https://jsfiddle.net/amzLkhru/

mr_jaro napisał(a):

wstaw sobie na czysto znak < i zobacz, w podglądzie kodu jak ładnie przeglądarka ci zaznacza, niepoprawne użycia znaku. Zrób np coś takiego 1 < 10, 10 > 1 a dostaniesz informacje "niepoprawny znacznik początkowy <10, 10>" dlatego, że każdy czysty znak <> jest odbierano jako html

Tak jest, ale Wy piszecie o wstawianiu na czysto; nie widzę, by działo się to samo, gdy używam document.createTextNode().

Freja Draco napisał(a):

Najprawdopodobniej ten twój skrypt zamienia każde & na &
W efekcie podwójnie zaencjowane < przyjmuje w kodzie postać &lt; i przestaje się wyświetlać jako <.

Nic podobnego mój skrypt nie robi. Na potrzeby testów zamieniałem wyłącznie < na &lt;, nie zamieniałem natomiast & na &amp;

Bardzo Wam dziękuję za odpowiedzi, jednakże upieram się, że w opisywanych przez Was wypadkach document.createTextNode() wyświetla te znaki jako czysty tekst, podczas gdy innerHTML interpretuje je jako HTML i jest podatny na XSS na sposób, jaki tu opisujemy, tj. za pomocą znaków < oraz >. Gdybym mógł prosić, byście spojrzeli na to: http://jsfiddle.net/3e6pngt4/11/ Zwróćcie proszę uwagę na to, w jaki sposób document.createTextNode() obsługuje stringi 1 &lt; 10 oraz "<a href="evil.com">Free iPhone click here</a>", a w jaki sposób czyni to innerHTML. Zamiana znaków specjalnych na encje wywołuje wadliwe wyświetlanie stringa wstawionego po stronie klienta za pomocą createTextNode().

Tym samym odnoszę wrażenie, iż createTextNode jest zaprojektowane, by nie wymagało sanityzacji stringa podanego mu jako argument w opisywany przez nas sposób.

Nie wykluczone natomiast, że potrzebuję sanityzować tegoż stringa na inne sposoby, by uniknąć ataków na

mr_jaro napisał(a):

20 innych sposób, np poprzez zabawę z kodami unicode.

Wówczas celem moim jest dowiedzieć się, jak mam go sanityzować :)

0
kmph napisał(a):

Tym samym odnoszę wrażenie, iż createTextNode jest zaprojektowane, by nie wymagało sanityzacji stringa podanego mu jako argument w opisywany przez nas sposób.

Dobra, przyłapałeś nas na odpisywaniu bez czytania :)
Faktycznie createTextNode działa właśnie w taki sposób, co jest nawet logiczne, zgodne z jego nazwą i przeznaczeniem:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_document_createtextnode

Niemniej zanim createTextNode przetworzy sobie tego stringa do czysto tekstowej postaci, musisz mu go najpierw jakoś w przekazać, a to już stwarza ryzyko nie tylko zrobienia XSS, ale nawet ataku na sam serwer / bazę.

0
Freja Draco napisał(a):

Niemniej zanim createTextNode przetworzy sobie tego stringa do czysto tekstowej postaci, musisz mu go najpierw jakoś w przekazać, a to już stwarza ryzyko nie tylko zrobienia XSS, ale nawet ataku na sam serwer / bazę.

Ah. I w związku z tym jak powinienem postępować?

0

Wydaje mi się, że po prostu trzeba to wyescapowac od razu po otrzymaniu od usera

np.

User -> server -> escape(input) -> database -> broadcast to otherUsers

https://www.w3.org/International/questions/qa-escapes#use

Syntax characters. There are three characters that should always appear in content as escapes, so that they do not interact with the syntax of the markup. These are part of the language for all documents based on HTML and for XML.

&lt; (<)

&gt; (>)

&amp; (&)

You may also want to represent the double-quote (") as " and the single quote (') as '. This would certainly be the case in attribute text when you need to use the same type of quotes as those that surround the attribute value.

0

Nie jestem frontendowcem, ale najlepiej w systemie nie escapować danych. Tzn. posługujesz się danymi w czystej postaci.
Dopiero gdy je wysyłasz do bazy danych czy na przeglądarkę to je escapujesz - w sposób do tego przewidziany.
Magiczne uniwersalne escapowanie wszystkiego było już trenowane w PHP i się nie sprawdziło.

Coś do poczytania:
https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet

0

@vpiotr: escapujesz przy zapisie danych a dodatkowo każdy porządny system wyświetlania też escapuje jeśli okaże się, że coś nadal jest niebezpieczne, np templatki blade, czy też dane wyświetlane przez angulara, vue itp. Jak się ktoś czystym js to musi też sam takie rzeczy obsłużyć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1