JavaScript 삽입 공격 방지(VB)

작성자 : Stephen Walther

JavaScript 삽입 공격 및 사이트 간 스크립팅 공격이 발생하지 않도록 방지합니다. 이 자습서에서 Stephen Walther는 콘텐츠를 HTML 인코딩하여 이러한 유형의 공격을 쉽게 무찌를 수 있는 방법을 설명합니다.

이 자습서의 목표는 ASP.NET MVC 애플리케이션에서 JavaScript 삽입 공격을 방지하는 방법을 설명하는 것입니다. 이 자습서에서는 JavaScript 삽입 공격으로부터 웹 사이트를 방어하는 두 가지 방법을 설명합니다. 표시되는 데이터를 인코딩하여 JavaScript 삽입 공격을 방지하는 방법을 알아봅니다. 또한 수락하는 데이터를 인코딩하여 JavaScript 삽입 공격을 방지하는 방법도 알아봅니다.

JavaScript 삽입 공격이란?

사용자 입력을 수락하고 사용자 입력을 다시 표시할 때마다 웹 사이트를 JavaScript 삽입 공격에 대해 엽니다. JavaScript 삽입 공격에 열려 있는 구체적인 애플리케이션을 살펴보겠습니다.

고객 피드백 웹 사이트를 만들었다고 상상해 보세요(그림 1 참조). 고객은 웹 사이트를 방문하여 제품을 사용하여 경험에 대한 피드백을 입력할 수 있습니다. 고객이 피드백을 제출하면 피드백 페이지에서 피드백이 다시 표시됩니다.

고객 피드백 웹 사이트

그림 01: 고객 피드백 웹 사이트(전체 크기 이미지를 보려면 클릭)

고객 피드백 웹 사이트는 목록 1의 controller 를 사용합니다. 여기에는 controller 및 라는 Index() 두 개의 작업이 포함됩니다 Create().

목록 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

메서드는 Index() 보기를 표시합니다 Index . 이 메서드는 데이터베이스에서 피드백을 Index 검색하여(LINQ to SQL 쿼리 사용) 이전 고객 피드백을 모두 보기에 전달합니다.

메서드는 Create() 새 피드백 항목을 만들고 데이터베이스에 추가합니다. 고객이 양식에 입력하는 메시지는 메시지 매개 변수의 Create() 메서드에 전달됩니다. 피드백 항목이 만들어지고 메시지가 피드백 항목의 Message 속성에 할당됩니다. 피드백 항목은 메서드 호출을 사용하여 데이터베이스에 DataContext.SubmitChanges() 제출됩니다. 마지막으로 방문자는 모든 피드백이 Index 표시되는 보기로 다시 리디렉션됩니다.

보기는 Index 목록 2에 포함되어 있습니다.

목록 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>

Index 보기에는 두 개의 섹션이 있습니다. 맨 위 섹션에는 실제 고객 피드백 양식이 포함되어 있습니다. 아래쪽 섹션에는 For.가 포함되어 있습니다. 각 루프는 이전의 모든 고객 피드백 항목을 반복하고 각 피드백 항목에 대한 EntryDate 및 메시지 속성을 표시합니다.

고객 피드백 웹 사이트는 간단한 웹 사이트입니다. 아쉽게도 웹 사이트는 JavaScript 삽입 공격에 열려 있습니다.

고객 피드백 양식에 다음 텍스트를 입력한다고 상상해 보세요.

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

이 텍스트는 경고 메시지 상자를 표시하는 JavaScript 스크립트를 나타냅니다. 누군가가 피드백 양식에 이 스크립트를 제출하면 Boo!은 나중에 고객 피드백 웹 사이트를 방문할 때마다 표시됩니다(그림 2 참조).

JavaScript 삽입

그림 02: JavaScript 삽입(전체 크기 이미지를 보려면 클릭)

이제 JavaScript 삽입 공격에 대한 초기 응답은 무관심할 수 있습니다. JavaScript 삽입 공격은 단순히 훼손 공격의 한 유형이라고 생각할 수 있습니다. JavaScript 삽입 공격을 커밋하여 아무도 진정으로 악한 일을 할 수 없다고 믿을 수 있습니다.

불행하게도, 해커는 웹 사이트에 JavaScript를 주입하여 정말, 정말 악한 일을 할 수 있습니다. JavaScript 삽입 공격을 사용하여 XSS(사이트 간 스크립팅) 공격을 수행할 수 있습니다. 사이트 간 스크립팅 공격에서 기밀 사용자 정보를 도용하고 정보를 다른 웹 사이트로 보냅니다.

예를 들어 해커는 JavaScript 삽입 공격을 사용하여 다른 사용자의 브라우저 쿠키 값을 도용할 수 있습니다. 암호, 신용 카드 번호 또는 사회 보장 번호와 같은 중요한 정보가 브라우저 쿠키에 저장되는 경우 해커는 JavaScript 삽입 공격을 사용하여 이 정보를 도용할 수 있습니다. 또는 사용자가 JavaScript 공격으로 손상된 페이지에 포함된 양식 필드에 중요한 정보를 입력하는 경우 해커는 삽입된 JavaScript를 사용하여 양식 데이터를 잡고 다른 웹 사이트로 보낼 수 있습니다.

무서워하세요. JavaScript 삽입 공격을 심각하게 받아들이고 사용자의 기밀 정보를 보호합니다. 다음 두 섹션에서는 JavaScript 삽입 공격으로부터 ASP.NET MVC 애플리케이션을 방어하는 데 사용할 수 있는 두 가지 기술에 대해 설명합니다.

접근 방식 #1: 보기의 HTML 인코딩

JavaScript 삽입 공격을 방지하는 한 가지 쉬운 방법은 보기에서 데이터를 다시 표시할 때 웹 사이트 사용자가 입력한 모든 데이터를 HTML로 인코딩하는 것입니다. 목록 3의 업데이트 Index 된 보기는 이 방법을 따릅니다.

목록 3 – Index.aspx (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>

feedback.Message 은 다음 코드와 함께 값이 표시되기 전에 HTML로 인코딩됩니다.

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

HTML에서 문자열을 인코딩한다는 것은 무엇을 의미하나요? 문자열을 HTML로 인코딩하면 및 와 같은 < 위험한 문자가 및 >&gt;와 같은 HTML 엔터티 참조로 &lt; 대체됩니다. 따라서 문자열 <script>alert("Boo!")</script> 이 HTML로 인코딩되면 로 변환 &lt;script&gt;alert(&quot;Boo!&quot;)&lt;/script&gt;됩니다. 브라우저에서 해석할 때 인코딩된 문자열은 더 이상 JavaScript 스크립트로 실행되지 않습니다. 대신 그림 3에서 무해한 페이지를 가져옵니다.

JavaScript 공격 패배

그림 03: 패배한 JavaScript 공격(전체 크기 이미지를 보려면 클릭)

목록 3의 Index 보기에서 값 feedback.Message 만 인코딩됩니다. 의 feedback.EntryDate 값은 인코딩되지 않습니다. 사용자가 입력한 데이터만 인코딩하면 됩니다. EntryDate 값이 컨트롤러에서 생성되었으므로 이 값을 HTML로 인코딩할 필요가 없습니다.

접근 방식 #2: 컨트롤러의 HTML 인코딩

뷰에 데이터를 표시할 때 HTML 인코딩 데이터 대신 데이터를 데이터베이스에 제출하기 직전에 데이터를 HTML로 인코딩할 수 있습니다. 이 두 번째 방법은 목록 4의 controller 경우 수행됩니다.

목록 4 – HomeController.cs (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

Message 값은 작업 내 Create() 의 데이터베이스에 값이 제출되기 전에 HTML로 인코딩됩니다. 보기에서 메시지가 다시 표시되면 메시지는 HTML로 인코딩되고 메시지에 삽입된 JavaScript는 실행되지 않습니다.

일반적으로 이 두 번째 방법보다 이 자습서에서 설명하는 첫 번째 방법을 선호해야 합니다. 이 두 번째 방법의 문제는 데이터베이스에서 HTML로 인코딩된 데이터로 끝난다는 것입니다. 즉, 데이터베이스 데이터는 재미있어 보이는 문자로 더러워집니다.

왜 이것이 나쁜가요? 웹 페이지 이외의 다른 항목에 데이터베이스 데이터를 표시해야 하는 경우 문제가 발생합니다. 예를 들어 더 이상 Windows Forms 애플리케이션에서 데이터를 쉽게 표시할 수 없습니다.

요약

이 자습서의 목적은 JavaScript 삽입 공격의 전망에 대해 겁을 주는 것이었습니다. 이 자습서에서는 JavaScript 삽입 공격으로부터 ASP.NET MVC 애플리케이션을 방어하는 두 가지 방법을 설명했습니다. 즉, 보기에서 사용자가 제출한 데이터를 HTML로 인코딩하거나 컨트롤러에서 사용자가 제출한 데이터를 HTML로 인코딩할 수 있습니다.