Skocz do zawartości

ASP.NET MVC: Wywoływanie funkcji JavaScript z parametrami z modelu


DevStart Blogi

Recommended Posts

Czasami w widoku wywołujemy funkcję JavaScript z parametrami, które są przekazane za pomocą ViewModel z kontrolera. Załóżmy, że nasza metoda w kontrolerze wygląda następująco:

       public ActionResult Index()
        {
            return View(new FooModel("Hello World!"));
        }

ViewModel z kolei zawiera jedną właściwość:

    public class FooModel
    {
        public string Text { get; set; }

        public FooModel(string text)
        {
            Text = text;
        }
    }

Następnie zdefiniujmy jakąkolwiek funkcję JS przyjmującą parametry:

<script type="text/javascript">
    function doSomethingInJs(text) {
        $('#sampleContainer').html(text);
    }
</script>

Błędne wywołanie funkcji w razor wygląda z kolei następująco:

 
   <script type="text/javascript">
        doSomethingInJs('@Model.Text');
    </script>

Jest to nic innego, jak klasyczny przykład wstrzyknięcia złośliwego kodu. Dotyczy to wszystkich pól typu string. Nawet jeśli spodziewamy się tylko imienia czy nazwiska, nigdy nie wiadomo jakie dane zawiera view model. Zwykle dane pochodzą z bazy danych. Co jeśli w jakiś sposób, baza danych zawiera już złośliwy kod? Aplikacja powinna traktować wszystkie dane, jako potencjalne zagrożenie.

Co jeśli, następująca treść zostanie przekazana?

    public ActionResult Index()
    {
            return View(new FooModel("<script>alert('Hello World')</script>"));
    }

Na szczęście powyższy kod jest bezpieczny, ponieważ Razor zamieni <script> na znaczniki HTML:

    <script type="text/javascript">
        $(function() {
           doSomethingInJs('&lt;script&gt;alert(&#39;Hello World&#39;)&lt;/script&gt;');
        });
    </script>

Innymi słowy, kod zostanie wyświetlony jak zwykły tekst. Za każdym razem, jak wywołujemy @Model, zawartość jest enkodowana. Co jednak stanie się, jeśli treść zostanie przekazana jako ASCII HEX?

public ActionResult Index()
{
   var text =       "\\x3c\\x73\\x63\\x72\\x69\\x70\\x74\\x3e\\x61\\x6c\\x65\\x72\\x74\\x28\\x27\\x48\\x65\\x6c\\x6c\\x6f\\x20\\x57\\x6f\\x72\\x6c\\x64\\x27\\x29\\x3c\\x2f\\x73\\x63\\x72\\x69\\x70\\x74\\x3e";

   return View(new FooModel(text));
}

Razor nie zakoduje treści ponieważ jest to zwykły tekst (brak znaczników HTML). Javascript z kolei, rozpoznaje ASCII w postaci hex (za pomocą \x). Efekt będzie taki, że kod javascript wykona się i wyświetli alert. W tej chwili, jeśli zajrzymy do źródła strony, zobaczymy:

 <script type="text/javascript">
        $(function() {
           doSomethingInJs('\x3c\x73\x63\x72\x69\x70\x74\x3e\x61\x6c\x65\x72\x74\x28\x27\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x27\x29\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e');
        });
  </script>

Rozwiązaniem jest endkodowanie parametrów funkcji JavaScript za pomocą HttpUtility.JavaScriptStringEncode:

    <script type="text/javascript">
        $(function() {
           doSomethingInJs('@HttpUtility.JavaScriptStringEncode(Model.Text)');
        });
    </script>

Efektem będzie:

    <script type="text/javascript">
        $(function() {           
doSomethingInJs('\\x3c\\x73\\x63\\x72\\x69\\x70\\x74\\x3e\\x61\\x6c\\x65\\x72\\x74\\x28\\x27\\x48\\x65\\x6c\\x6c\\x6f\\x20\\x57\\x6f\\x72\\x6c\\x64\\x27\\x29\\x3c\\x2f\\x73\\x63\\x72\\x69\\x70\\x74\\x3e');
        });
    </script>

Widzimy, że każdy kod ascii, zostały poprzedzony dodatkowym znakiem ‘\’.

Generalnie połączenie jQuery + mieszanie C# z JavaScript jest nie tylko złą praktyką z punktu widzenia bezpieczeństwa, ale również nie jest to zbyt czysty kod. Nie powinno mieszać się kodu inline z szablonami razor. Te dwie warstwy powinny rozwijać się niezależnie. Da nam to nie tylko łatwiejszy w utrzymaniu kod, ale również jak widać powyżej, łatwiej będzie uniknąć luk w bezpieczeństwie.

Wyświetl pełny artykuł

Link do komentarza
Udostępnij na innych stronach

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gość
Odpowiedz...

×   Wkleiłeś zawartość bez formatowania.   Usuń formatowanie

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Utwórz nowe...