Zapobieganie atakom polegającym na wstrzyknięciu kodu JavaScript (VB)

Autor: Stephen Walther

Zapobiegaj atakom polegającym na wstrzyknięciu kodu JavaScript i atakom skryptowym między witrynami. W tym samouczku Stephen Walther wyjaśnia, jak można łatwo pokonać te typy ataków przez kodowanie zawartości html.

Celem tego samouczka jest wyjaśnienie, w jaki sposób można zapobiec atakom polegającym na wstrzyknięciu kodu JavaScript w aplikacjach MVC ASP.NET. W tym samouczku omówiono dwa podejścia do obrony witryny internetowej przed atakiem polegającym na wstrzyknięciu kodu JavaScript. Dowiesz się, jak zapobiegać atakom polegającym na wstrzyknięciu kodu JavaScript przez kodowanie wyświetlanych danych. Dowiesz się również, jak zapobiegać atakom polegającym na wstrzyknięciu kodu JavaScript przez kodowanie akceptowanych danych.

Co to jest atak polegający na wstrzyknięciu kodu JavaScript?

Za każdym razem, gdy akceptujesz dane wejściowe użytkownika i redisplay danych wejściowych użytkownika, otwierasz witrynę internetową do ataków polegających na wstrzyknięciu kodu JavaScript. Przeanalizujmy konkretną aplikację, która jest otwarta dla ataków polegających na wstrzyknięciu kodu JavaScript.

Załóżmy, że utworzono witrynę internetową opinii klientów (zobacz Rysunek 1). Klienci mogą odwiedzać witrynę internetową i wprowadzać opinie dotyczące korzystania z Twoich produktów. Gdy klient prześle swoją opinię, opinia zostanie ponownie odtworzona na stronie opinii.

Witryna internetowa opinii klientów

Rysunek 01. Witryna internetowa opinii klientów (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Witryna internetowa opinii klientów korzysta z listy controller 1. Zawiera controller dwie akcje o nazwach Index() i Create().

Lista 1 — HomeController.vb

Public Class HomeController
     Inherits System.Web.Mvc.Controller

     Private db As New FeedbackDataContext()

     Function Index()
          Return View(db.Feedbacks)
     End Function

     Function Create(ByVal message As String)
          ' Add feedback
          Dim newFeedback As New Feedback()
          newFeedback.Message = Server.HtmlEncode(message)

          newFeedback.EntryDate = DateTime.Now
          db.Feedbacks.InsertOnSubmit(newFeedback)
          db.SubmitChanges()

          ' Redirect
          Return RedirectToAction("Index")
     End Function

End Class

Metoda Index() wyświetla Index widok. Ta metoda przekazuje wszystkie poprzednie opinie klientów do Index widoku przez pobranie opinii z bazy danych (przy użyciu zapytania LINQ to SQL).

Metoda Create() tworzy nowy element Opinii i dodaje go do bazy danych. Komunikat wprowadzony przez klienta w formularzu jest przekazywany do Create() metody w parametrze komunikatu. Element opinia jest tworzony i komunikat jest przypisywany Message do właściwości elementu Opinia. Element Opinia jest przesyłany do bazy danych za pomocą wywołania DataContext.SubmitChanges() metody. Na koniec gość jest przekierowywany z powrotem do Index widoku, w którym są wyświetlane wszystkie opinie.

Widok Index znajduje się na liście 2.

Lista 2 — Index.aspx

<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="false" CodeBehind="Index.aspx.vb" Inherits="CustomerFeedback.Index"%>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
     <h1>Customer Feedback</h1>
     <p>
          Please use the following form to enter feedback about our product.
     </p>
     <form method="post" action="/Home/Create">
          <label for="message">Message:</label>

          <br />
          <textarea name="message" cols="50" rows="2"></textarea>
          <br /><br />
          <input type="submit" value="Submit Feedback" />
     </form>

     <% For Each feedback As CustomerFeedback.Feedback In ViewData.Model%>
          <p>

          <%=feedback.EntryDate.ToShortTimeString()%>
          --
          <%=feedback.Message%>
          </p>
     <% Next %>

</asp:Content>

Widok Index zawiera dwie sekcje. Górna sekcja zawiera rzeczywisty formularz opinii klientów. Dolna sekcja zawiera element For.. Każda pętla, która przechodzi przez wszystkie poprzednie elementy opinii klientów i wyświetla właściwości EntryDate i Message dla każdego elementu opinii.

Witryna internetowa opinii klientów jest prostą witryną internetową. Niestety witryna internetowa jest otwarta dla ataków polegających na wstrzyknięciu kodu JavaScript.

Załóżmy, że wprowadzasz następujący tekst w formularzu opinii klientów:

<script>alert("Boo!")</script>

Ten tekst reprezentuje skrypt JavaScript, który wyświetla okno komunikatu alertu. Po przesłaniu tego skryptu do formularza opinii wiadomość boo!będzie wyświetlany za każdym razem, gdy każda osoba odwiedzi witrynę internetową opinii klientów w przyszłości (zobacz Rysunek 2).

Wstrzykiwanie kodu JavaScript

Rysunek 02. Wstrzykiwanie kodu JavaScript (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Teraz początkową odpowiedzią na ataki iniekcji języka JavaScript mogą być apatia. Być może uważasz, że ataki iniekcji kodu JavaScript są po prostu typem ataku defacement . Możesz uwierzyć, że nikt nie może zrobić nic naprawdę złego, popełniając atak polegający na wstrzyknięciu kodu JavaScript.

Niestety, haker może zrobić kilka naprawdę, naprawdę złe rzeczy, wstrzykiwając JavaScript do witryny internetowej. Atak polegający na wstrzyknięciu kodu JavaScript umożliwia przeprowadzenie ataku typu skryptów między witrynami (XSS). W przypadku ataku opartego na skryptach między witrynami przechwycisz poufne informacje o użytkowniku i wyślesz informacje do innej witryny internetowej.

Na przykład haker może użyć ataku iniekcji języka JavaScript, aby ukraść wartości plików cookie przeglądarki od innych użytkowników. Jeśli informacje poufne — takie jak hasła, numery kart kredytowych lub numery ubezpieczenia społecznego — są przechowywane w plikach cookie przeglądarki, haker może użyć ataku polegającego na wstrzyknięciu kodu JavaScript w celu kradzieży tych informacji. Lub jeśli użytkownik wprowadzi poufne informacje w polu formularza znajdującym się na stronie, która została naruszona w wyniku ataku w języku JavaScript, haker może użyć wprowadzonego kodu JavaScript, aby pobrać dane formularza i wysłać je do innej witryny internetowej.

Proszę być przestraszony. Poważnie traktuj ataki polegające na wstrzyknięciu kodu JavaScript i chroń poufne informacje użytkownika. W kolejnych dwóch sekcjach omówiono dwie techniki, których można użyć do obrony ASP.NET aplikacji MVC przed atakami polegającymi na wstrzyknięciu kodu JavaScript.

Podejście nr 1: Kodowanie HTML w widoku

Jedną z prostych metod zapobiegania atakom polegającym na wstrzyknięciu kodu JavaScript jest kodowanie wszystkich danych wprowadzonych przez użytkowników witryny internetowej podczas ponownego redystrygowania danych w widoku. Zaktualizowany Index widok na liście 3 jest zgodny z tą metodą.

Lista 3 — Index.aspx (zakodowana w formacie HTML)

<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="false" CodeBehind="Index.aspx.vb" Inherits="CustomerFeedback.Index"%>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
     <h1>Customer Feedback</h1>

     <p>
          Please use the following form to enter feedback about our product.
     </p>

     <form method="post" action="/Home/Create">
          <label for="message">Message:</label>
          <br />
          <textarea name="message" cols="50" rows="2"></textarea>

          <br /><br />
          <input type="submit" value="Submit Feedback" />
     </form>

     <% For Each feedback As CustomerFeedback.Feedback In ViewData.Model%>
          <p>
          <%=feedback.EntryDate.ToShortTimeString()%>
          --
          <%=Html.Encode(feedback.Message)%>

          </p>
     <% Next %>

</asp:Content>

Zwróć uwagę, że wartość feedback.Message elementu jest zakodowana w formacie HTML przed wyświetleniem wartości przy użyciu następującego kodu:

<%=Html.Encode(feedback.Message)%>

Co to znaczy kodować ciąg w języku HTML? Gdy kodujesz ciąg w języku HTML, niebezpieczne znaki, takie jak < i > , są zastępowane odwołaniami do jednostek HTML, takimi jak &lt; i &gt;. Dlatego gdy ciąg <script>alert("Boo!")</script> jest zakodowany w formacie HTML, jest konwertowany na &lt;script&gt;alert(&quot;Boo!&quot;)&lt;/script&gt;wartość . Zakodowany ciąg nie jest już wykonywany jako skrypt języka JavaScript w przypadku interpretowania przez przeglądarkę. Zamiast tego uzyskasz nieszkodliwą stronę na rysunku 3.

Pokonany atak w języku JavaScript

Rysunek 03. Pokonany atak w języku JavaScript (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Zwróć uwagę, że w Index widoku na liście 3 jest zakodowana tylko wartość .feedback.Message Wartość feedback.EntryDate nie jest zakodowana. Wystarczy zakodować dane wprowadzone przez użytkownika. Ponieważ wartość EntryDate została wygenerowana w kontrolerze, nie trzeba kodować tej wartości w kodzie HTML.

Podejście nr 2: Kodowanie HTML w kontrolerze

Zamiast kodowania HTML podczas wyświetlania danych w widoku, można kodować dane HTML tuż przed przesłaniem danych do bazy danych. To drugie podejście jest podejmowane w przypadku listy controller 4.

Lista 4 — HomeController.cs (zakodowana w formacie HTML)

Public Class HomeController
     Inherits System.Web.Mvc.Controller

     Private db As New FeedbackDataContext()

     Function Index()
          Return View(db.Feedbacks)
     End Function

     Function Create(ByVal message As String)
          ' Add feedback
          Dim newFeedback As New Feedback()
          newFeedback.Message = Server.HtmlEncode(message)
          newFeedback.EntryDate = DateTime.Now
          db.Feedbacks.InsertOnSubmit(newFeedback)
          db.SubmitChanges()

          ' Redirect
          Return RedirectToAction("Index")
     End Function

End Class

Zwróć uwagę, że wartość Message jest zakodowana w formacie HTML przed przesłaniem wartości do bazy danych w ramach Create() akcji. Gdy komunikat jest ponownie odtwarzany w widoku, komunikat jest zakodowany w formacie HTML, a kod JavaScript wstrzyknięty w komunikacie nie jest wykonywany.

Zazwyczaj należy stosować pierwsze podejście omówione w tym samouczku w ramach drugiego podejścia. Problem z tym drugim podejściem polega na tym, że w końcu dane zakodowane w języku HTML w bazie danych. Innymi słowy, dane bazy danych są brudne z zabawnymi postaciami.

Dlaczego jest to złe? Jeśli kiedykolwiek musisz wyświetlić dane bazy danych w innej niż strona internetowa, wystąpią problemy. Na przykład nie można już łatwo wyświetlać danych w aplikacji Windows Forms.

Podsumowanie

Celem tego samouczka było przestraszenie cię o perspektywę ataku iniekcji języka JavaScript. W tym samouczku omówiono dwie metody ochrony aplikacji MVC ASP.NET przed atakami polegającymi na wstrzyknięciu kodu JavaScript: możesz kodować dane przesłane przez użytkownika w kodzie HTML w widoku lub kodować dane przesłane przez użytkownika w kontrolerze.