Wskazówki dotyczące ograniczania zagrożeń na potrzeby interaktywnego renderowania po stronie serwera ASP.NET Core Blazor

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.

W tym artykule wyjaśniono, jak ograniczyć zagrożenia bezpieczeństwa w interaktywnym komponencie Blazor po stronie serwera.

Aplikacje przyjmują stanowy model przetwarzania danych, w którym serwer i klient utrzymują długotrwałą relację. Stan trwały jest utrzymywany przez obwód, który może obejmować połączenia, które również są potencjalnie długotrwałe.

Gdy użytkownik odwiedza lokację, serwer tworzy obwód w pamięci serwera. Obwód wskazuje przeglądarce zawartość, która ma być renderowana i odpowiada na zdarzenia, na przykład gdy użytkownik wybierze przycisk w interfejsie użytkownika. Aby wykonać te akcje, obwód wywołuje funkcje JavaScript w przeglądarce użytkownika i metodach platformy .NET na serwerze. Ta dwukierunkowa interakcja oparta na języku JavaScript jest określana mianem JavaScript interop (JSinterop).

Ponieważ interoperacyjność JS odbywa się przez Internet, a klient korzysta z przeglądarki uruchomionej zdalnie, aplikacje mają większość takich samych problemów z bezpieczeństwem jak aplikacje internetowe. W tym temacie opisano typowe zagrożenia dla aplikacji po stronie Blazor serwera i przedstawiono wskazówki dotyczące ograniczania zagrożeń ukierunkowane na aplikacje dostępne z Internetu.

W środowiskach ograniczonych, takich jak wewnątrz sieci firmowych lub intranetów, niektóre wskazówki dotyczące ograniczania ryzyka:

  • Nie ma zastosowania w środowisku ograniczonym.
  • Nie jest wart koszt wdrożenia, ponieważ ryzyko bezpieczeństwa jest niskie w środowisku ograniczonym.

Interakcyjne składniki serwera z włączoną kompresją protokołu WebSocket

Kompresja może narazić aplikację na ataki z użyciem kanału bocznego wymierzone w szyfrowanie TLS połączenia, takie jak ataki CRIME i BREACH. Tego typu ataki wymagają, aby cyberprzestępca:

  • Zmusić przeglądarkę do wysyłania do podatnej witryny żądań z ładunkiem kontrolowanym przez cyberatakującego za pośrednictwem przesyłania formularzy między witrynami lub przez osadzenie tej witryny w ramce iframe innej witryny.
  • Obserwuj długość skompresowanej i zaszyfrowanej odpowiedzi za pośrednictwem sieci.

Aby aplikacja była podatna, musi zwracać w odpowiedzi ładunek danych przesłany przez cyberatakującego, na przykład przez zapisanie w odpowiedzi ścieżki lub parametrów zapytania. Wykorzystując długość odpowiedzi, cyberatakujący może „odgadnąć” dowolne informacje zawarte w odpowiedzi, obchodząc szyfrowanie połączenia.

Ogólnie rzecz biorąc, Blazor aplikacje mogą włączyć kompresję za pośrednictwem połączenia protokołu WebSocket z odpowiednimi środkami zabezpieczeń:

  • Aplikacja może być podatna na zagrożenia, gdy pobiera zawartość z żądania (na przykład ścieżkę lub ciąg zapytania), na które może mieć wpływ cyberatak i odtwarza ją w kodzie HTML strony lub w inny sposób sprawia, że jest częścią odpowiedzi.

  • Blazor stosuje następujące środki zabezpieczeń automatycznie:

    • Gdy skonfigurowano kompresję, Blazor automatycznie blokuje osadzanie aplikacji w elemencie iframe, co uniemożliwia wyrenderowanie początkowej (nieskompresowanej) odpowiedzi z serwera i sprawia, że połączenie WebSocket nigdy nie zostaje nawiązane.

    • Ograniczenie osadzania aplikacji w ramce iframe może być złagodzone. Jednak złagodzenie ograniczeń naraża aplikację na atak, jeśli dokument osadzania zostanie naruszony za pośrednictwem luki w zabezpieczeniach skryptów między witrynami, ponieważ daje to cyberatakom sposób na wykonanie ataku.

  • Zwykle w przypadku tego typu ataku aplikacja musi wielokrotnie odtwarzać zawartość w odpowiedziach, aby cyberataka mogła odgadnąć odpowiedź. Biorąc pod uwagę sposób renderowania przez Blazor (renderuje on jeden raz, a następnie generuje różnice w treści wyłącznie dla elementów, które uległy zmianie), jest to trudne do osiągnięcia dla cyberatakującego. Jednak nie jest to niemożliwe dla cyberataki, więc należy zadbać, aby uniknąć renderowania poufnych informacji wraz z informacjami zewnętrznymi, które mogą być manipulowane przez cyberatakę. Oto kilka przykładów:

    • Renderować na stronie dane umożliwiające identyfikację osoby (PII) jednocześnie z danymi z bazy danych dodanymi przez innego użytkownika.

    • Wyświetlanie danych osobowych na stronie jednocześnie z danymi pochodzącymi od innego użytkownika za pośrednictwem mechanizmu JS interop lub lokalnej usługi singletonowej na serwerze.

Ogólnie rzecz biorąc, zalecamy unikanie renderowania składników zawierających poufne informacje wraz ze składnikami, które mogą renderować dane z niezaufanych źródeł w ramach tej samej partii renderowania. Niezaufane źródła obejmują parametry trasy, parametry zapytania, dane pochodzące z mechanizmu JS interop oraz wszelkie inne źródła danych, które mogą być kontrolowane przez użytkownika zewnętrznego (takie jak bazy danych i usługi zewnętrzne).

Stan współdzielony

Aplikacje po stronie Blazor serwera działają w pamięci serwera, a wiele sesji aplikacji jest hostowanych w ramach tego samego procesu. Dla każdej sesji aplikacji element Blazor inicjuje obwód z własnym zakresem kontenera iniekcji zależności, dlatego usługi zakresowe są unikatowe dla sesji Blazor.

Ostrzeżenie

Nie zalecamy, aby aplikacje na tym samym serwerze współdzieliły stan za pomocą usług singleton, chyba że zachowana zostanie szczególna ostrożność, ponieważ może to prowadzić do luk w zabezpieczeniach, takich jak wyciek stanu użytkownika między obwodami.

Możesz używać stanowych usług typu singleton w aplikacjach Blazor, jeśli zostały specjalnie do tego zaprojektowane. Na przykład użycie pamięci podręcznej typu singleton jest dopuszczalne, ponieważ pamięć podręczna wymaga klucza, aby uzyskać dostęp do danego wpisu. Zakładając, że użytkownicy nie mają kontroli nad kluczami pamięci podręcznej używanymi z pamięcią podręczną, stan przechowywany w pamięci podręcznej nie przecieka między obwodami.

Aby uzyskać ogólne wskazówki dotyczące zarządzania stanem, zobacz omówienie zarządzania stanem ASP.NET CoreBlazor.

IHttpContextAccessor/HttpContext

Aby uzyskać więcej informacji, zobacz IHttpContextAccessor/HttpContext w aplikacjach ASP.NET Core Blazor.

Wyczerpanie zasobów

Wyczerpanie zasobów może wystąpić, gdy klient wchodzi w interakcję z serwerem i powoduje, że serwer zużywa nadmierne zasoby. Nadmierne użycie zasobów ma wpływ przede wszystkim na:

Ataki typu "odmowa usługi" (DoS) zwykle próbują wyczerpać zasoby aplikacji lub serwera. Jednak wyczerpanie zasobów niekoniecznie jest wynikiem ataku na system. Na przykład ograniczone zasoby mogą być wyczerpane z powodu wysokiego zapotrzebowania użytkowników. Usługa DoS jest dokładniej omówiona w sekcji DoS.

Zasoby zewnętrzne wobec frameworka Blazor, takie jak bazy danych i uchwyty plików (używane do odczytu i zapisu plików), również mogą ulec wyczerpaniu. Aby uzyskać więcej informacji, zobacz ASP.NET Core Best Practices (Najlepsze rozwiązania podstawowe).

CPU

Wyczerpanie procesora CPU może wystąpić, gdy co najmniej jeden klient wymusi na serwerze wykonywanie intensywnej pracy procesora CPU.

Rozważmy na przykład aplikację, która oblicza liczbę Fibonnacciego. Liczba Fibonnacciego jest generowana z sekwencji Fibonnacciego, gdzie każda liczba w sekwencji jest sumą dwóch poprzednich liczb. Ilość pracy wymaganej do uzyskania odpowiedzi zależy od długości sekwencji i rozmiaru wartości początkowej. Jeśli aplikacja nie umieszcza limitów w żądaniu klienta, obliczenia intensywnie korzystające z procesora CPU mogą zdominować czas procesora i zmniejszyć wydajność innych zadań. Nadmierne użycie zasobów jest problemem zabezpieczeń wpływającym na dostępność.

Przeciążenie procesora stanowi problem dla wszystkich publicznie dostępnych aplikacji. W zwykłych aplikacjach internetowych żądania i połączenia wygasają po określonym czasie w ramach zabezpieczenia, ale aplikacje Blazor nie zapewniają takich samych zabezpieczeń. Blazor aplikacje muszą uwzględniać odpowiednie sprawdzenia i limity przed rozpoczęciem potencjalnie obciążających procesor zadań.

Pamięć

Wyczerpanie pamięci może wystąpić, gdy co najmniej jeden klient wymusi na serwerze użycie dużej ilości pamięci.

Rozważmy na przykład aplikację ze składnikiem, który akceptuje i wyświetla listę elementów. Blazor Jeśli aplikacja nie umieszcza limitów liczby dozwolonych elementów lub liczby elementów renderowanych z powrotem do klienta, przetwarzanie intensywnie korzystające z pamięci i renderowanie może zdominować pamięć serwera do punktu, w którym wydajność serwera ucierpi. Serwer może ulec awarii lub spowolnić do tego stopnia, że będzie sprawiał wrażenie, jakby uległ awarii.

Rozważmy następujący scenariusz obsługi i wyświetlania listy elementów odnoszących się do potencjalnego scenariusza wyczerpania pamięci na serwerze:

  • Elementy we właściwości lub polu List<T> zajmują pamięć serwera. Jeśli aplikacja pozwala, aby lista elementów rosła bez ograniczeń, istnieje ryzyko, że na serwerze zabraknie pamięci. Wyczerpanie pamięci powoduje zakończenie bieżącej sesji (ulega ona awarii) oraz sprawia, że wszystkie współbieżne sesje w tym wystąpieniu serwera otrzymują wyjątek braku pamięci. Aby zapobiec wystąpieniu tego scenariusza, aplikacja musi używać struktury danych, która nakłada limit elementów na współbieżnych użytkowników.
  • Jeśli schemat stronicowania nie jest używany do renderowania, serwer używa dodatkowej pamięci dla obiektów, które nie są widoczne w interfejsie użytkownika. Bez limitu liczby elementów zapotrzebowanie na pamięć może wyczerpać dostępną pamięć serwera. Aby zapobiec temu scenariuszowi, użyj jednego z następujących podejść:
    • Używaj list stronicowanych podczas renderowania.
    • Wyświetla tylko pierwsze 100 do 1000 elementów i wymaga od użytkownika wprowadzenia kryteriów wyszukiwania w celu znalezienia elementów poza wyświetlanymi elementami.
    • W przypadku bardziej zaawansowanego scenariusza renderowania zaimplementuj listy lub siatki, które obsługują wirtualizację. Przy użyciu wirtualizacji listy renderuje tylko podzbiór elementów, które są obecnie widoczne dla użytkownika. Gdy użytkownik wchodzi w interakcję z paskiem przewijania w interfejsie użytkownika, składnik renderuje tylko te elementy wymagane do wyświetlenia. Elementy, które nie są obecnie wymagane do wyświetlania, mogą być przechowywane w magazynie pomocniczym, co jest idealnym rozwiązaniem. Niewyświetlane elementy mogą być również przechowywane w pamięci, co nie jest rozwiązaniem optymalnym.

Uwaga

Blazor ma wbudowaną obsługę wirtualizacji. Aby uzyskać więcej informacji, zobacz wirtualizację składników w technologii ASP.NET CoreRazor.

Blazor aplikacje oferują podobny model programowania do innych struktur interfejsu użytkownika dla aplikacji stanowych, takich jak WPF, Windows Forms lub Blazor WebAssembly. Główną różnicą jest to, że w kilku strukturach interfejsu użytkownika pamięć zużywana przez aplikację należy do klienta i dotyczy tylko tego pojedynczego klienta. Na przykład Blazor WebAssembly aplikacja działa całkowicie na kliencie i używa tylko zasobów pamięci klienta. W przypadku aplikacji Blazor po stronie serwera pamięć zużywana przez aplikację jest przypisana do serwera i jest współdzielona między klientami w instancji serwera.

Wymagania dotyczące pamięci po stronie serwera są istotne dla wszystkich aplikacji po stronie Blazor serwera. Jednak większość aplikacji internetowych jest bezstanowa, a pamięć używana podczas przetwarzania żądania jest zwalniana po zwróceniu odpowiedzi. Ogólnie rzecz biorąc, nie zezwalaj klientom na przydzielanie niezwiązanej ilości pamięci, tak jak w przypadku każdej innej aplikacji po stronie serwera, która utrzymuje połączenia klienta. Pamięć zużywana przez aplikację po stronie Blazor serwera jest zachowywana przez dłuższy czas niż pojedyncze żądanie.

Uwaga

Podczas tworzenia można użyć profilera lub zarejestrować ślad, aby ocenić zapotrzebowanie klientów na pamięć. Profiler ani śledzenie nie uchwycą pamięci przydzielonej konkretnemu klientowi. Aby sprawdzić wykorzystanie pamięci przez określonego klienta podczas tworzenia, utwórz zrzut pamięci i zbadaj zużycie pamięci wszystkich obiektów osiągalnych z obwodu użytkownika.

Połączenia klienta

Wyczerpanie połączeń może wystąpić, gdy co najmniej jeden klient otwiera zbyt wiele współbieżnych połączeń z serwerem, uniemożliwiając innym klientom nawiązywanie nowych połączeń.

Blazor klienci ustanawiają pojedyncze połączenie na sesję i utrzymują otwarte połączenie tak długo, jak okno przeglądarki jest otwarte. Biorąc pod uwagę trwały charakter połączeń i stanowy charakter aplikacji po stronie Blazor serwera, wyczerpanie połączeń jest większym ryzykiem dostępności aplikacji.

Nie ma limitu liczby połączeń na użytkownika dla aplikacji. Jeśli aplikacja wymaga limitu połączenia, wykonaj co najmniej jedną z następujących metod:

  • Wymagaj uwierzytelniania, co naturalnie ogranicza możliwość nieautoryzowanego łączenia użytkowników z aplikacją. Aby ten scenariusz był skuteczny, należy uniemożliwić użytkownikom prowizjonowanie nowych użytkowników na żądanie.
  • Ogranicz liczbę połączeń na użytkownika. Ograniczanie połączeń można osiągnąć za pomocą poniższych metod. Należy zachować ostrożność, aby umożliwić uprawnionym użytkownikom dostęp do aplikacji (na przykład po ustanowieniu limitu połączenia na podstawie adresu IP klienta).
    • Poziom aplikacji
      • Rozszerzalność routingu punktów końcowych.
      • Wymagaj uwierzytelnienia, aby połączyć się z aplikacją i śledzić aktywne sesje dla każdego użytkownika.
      • Odrzuć nowe sesje po osiągnięciu limitu.
      • Przekazuj połączenia WebSocket do aplikacji za pośrednictwem serwera proxy, takiego jak Azure SignalR Service, który multipleksuje połączenia od klientów do aplikacji. Zapewnia to aplikacji większą pojemność połączenia niż jeden klient może ustanowić, uniemożliwiając klientowi wyczerpanie połączeń z serwerem.
    • Poziom serwera: użyj serwera proxy/bramy sieciowej przed aplikacją.
  • Wymagaj uwierzytelniania, co naturalnie ogranicza możliwość nieautoryzowanego łączenia użytkowników z aplikacją. Aby ten scenariusz był skuteczny, należy uniemożliwić użytkownikom aprowizowanie nowych użytkowników na żądanie.
  • Ogranicz liczbę połączeń na użytkownika. Ograniczanie połączeń można osiągnąć za pomocą poniższych metod. Należy zachować ostrożność, aby umożliwić uprawnionym użytkownikom dostęp do aplikacji (na przykład po ustanowieniu limitu połączenia na podstawie adresu IP klienta).
    • Poziom aplikacji
      • Rozszerzalność routingu punktów końcowych.
      • Wymagaj uwierzytelnienia do połączenia z aplikacją i śledź aktywne sesje dla każdego użytkownika.
      • Odrzuć nowe sesje po osiągnięciu limitu.
      • Przekazuj połączenia WebSocket do aplikacji za pośrednictwem serwera proxy, takiego jak Azure SignalR Service, który multipleksuje połączenia od klientów do aplikacji. Zapewnia to aplikacji większą pojemność połączenia niż jeden klient może ustanowić, uniemożliwiając klientowi wyczerpanie połączeń z serwerem.
    • Poziom serwera

Ataki typu "odmowa usługi" (DoS)

Ataki typu "odmowa usługi" (DoS) obejmują klienta, który powoduje wyczerpanie jednego lub większej liczby zasobów, dzięki czemu aplikacja jest niedostępna. Blazor aplikacje mają domyślne limity i polegają na innych limitach ASP.NET Core i SignalR, które są ustawione na CircuitOptions w celu ochrony przed atakami DoS:

Aby uzyskać więcej informacji i przykładów kodowania konfiguracji, zobacz następujące artykuły:

Interakcje z przeglądarką (klientem)

Klient komunikuje się z serwerem za pośrednictwem wywoływania zdarzeń interop JS i zakończenia renderowania. JS Komunikacja międzyoperacyjna odbywa się na oba sposoby między językiem JavaScript i platformą .NET:

  • Zdarzenia przeglądarki są wysyłane z klienta do serwera w sposób asynchroniczny.
  • Serwer odpowiada asynchronicznie, w razie potrzeby ponownie renderując interfejs użytkownika.

Funkcje języka JavaScript wywoływane z platformy .NET

W przypadku wywołań z metod platformy .NET do języka JavaScript:

  • Wszystkie wywołania mają konfigurowalny limit czasu, po którym kończą się niepowodzeniem, zwracając element OperationCanceledException do elementu wywołującego.
  • Wynik wywołania języka JavaScript nie może być zaufany. Klient Blazor aplikacji uruchomiony w przeglądarce wyszukuje funkcję JavaScript do wywołania. Wywoływana jest funkcja, a wynik lub błąd jest generowany. Złośliwy klient może próbować:
    • Spowoduj problem w aplikacji, zwracając błąd z funkcji JavaScript.
    • Wywołaj niezamierzone zachowanie na serwerze, zwracając nieoczekiwany wynik z funkcji JavaScript.

Aby chronić się przed poprzednimi scenariuszami, wykonaj następujące środki ostrożności:

  • Umieszczaj wywołania interop JS w instrukcjach try-catch, aby obsłużyć błędy, które mogą wystąpić podczas ich wykonywania. Aby uzyskać więcej informacji, zobacz temat Obsługa błędów w aplikacjach Blazor platformy ASP.NET Core.
  • Przed podjęciem jakiejkolwiek akcji zweryfikuj dane zwrócone z JS wywołań międzyoperacyjnych, w tym komunikaty o błędach.

Metody platformy .NET wywoływane z przeglądarki

Nie ufaj wywołaniom języka JavaScript do metod platformy .NET. Gdy metoda platformy .NET jest udostępniona dla języka JavaScript, weź pod uwagę sposób wywoływania metody .NET:

  • Każdą metodę .NET udostępnianą środowisku JavaScript należy traktować tak samo jak publiczny punkt końcowy aplikacji.
    • Zweryfikuj dane wejściowe.
      • Upewnij się, że wartości znajdują się w oczekiwanych zakresach.
      • Upewnij się, że użytkownik ma uprawnienia do wykonania żądanej akcji.
    • Nie przydzielaj nadmiernej ilości zasobów w ramach wywołania metody .NET. Na przykład przeprowadzaj kontrole i umieszczaj limity użycia procesora CPU i pamięci.
    • Należy wziąć pod uwagę, że metody statyczne i metody wystąpień mogą być widoczne dla klientów języka JavaScript. Unikaj udostępniania stanu między sesjami, chyba że projekt wymaga udostępniania stanu z odpowiednimi ograniczeniami.
      • W przypadku metod wystąpień uwidocznionych za pośrednictwem DotNetObjectReference obiektów, które są pierwotnie tworzone za pośrednictwem wstrzykiwania zależności (DI), obiekty powinny być rejestrowane jako obiekty o określonym zakresie. Dotyczy to dowolnej usługi di używanej przez aplikację.
      • W przypadku metod statycznych należy unikać tworzenia stanu, którego nie można przypisać do klienta, chyba że aplikacja zgodnie z założeniami jawnie współdzieli stan między wszystkimi użytkownikami w ramach instancji serwera.
    • Unikaj przekazywania danych dostarczonych przez użytkownika w parametrach do wywołań języka JavaScript. Jeśli przekazywanie danych w parametrach jest absolutnie wymagane, upewnij się, że kod JavaScript obsługuje przekazywanie danych bez wprowadzania luk w zabezpieczeniach skryptów między witrynami (XSS ). Na przykład nie zapisuj danych dostarczonych przez użytkownika do modelu DOM, ustawiając innerHTML właściwość elementu. Rozważ użycie zasad zabezpieczeń zawartości (CSP), aby wyłączyć eval i inne niebezpieczne elementy pierwotne języka JavaScript. Aby uzyskać więcej informacji, zobacz Wymuszanie zasad zabezpieczeń zawartości dla ASP.NET Core Blazor i MDN CSP przewodnik.
  • Unikaj implementowania niestandardowego mechanizmu wywoływania wywołań .NET w oparciu o implementację wywoływania zapewnianą przez platformę. Uwidacznianie metod platformy .NET w przeglądarce jest zaawansowanym scenariuszem, który nie jest zalecany w przypadku ogólnego Blazor programowania.

Zdarzenia

Zdarzenia zapewniają punkt wejścia do aplikacji. Te same reguły ochrony punktów końcowych w aplikacjach internetowych mają zastosowanie do obsługi zdarzeń w Blazor aplikacjach. Złośliwy klient może przesłać jako treść zdarzenia dowolne dane, jakie zechce.

Na przykład:

  • Zdarzenie zmiany elementu <select> może wysłać wartość, która nie znajduje się w opcjach przedstawionych klientowi przez aplikację.
  • Obiekt <input> może wysyłać dowolne dane tekstowe na serwer, pomijając weryfikację po stronie klienta.

Aplikacja musi zweryfikować dane dla dowolnego zdarzenia obsługiwanego przez aplikację. Komponenty formularzy Blazorframeworka przeprowadzają podstawową walidację. Jeśli aplikacja używa niestandardowych składników formularzy, należy napisać kod niestandardowy w celu zweryfikowania danych zdarzenia zgodnie z potrzebami.

Zdarzenia są asynchroniczne, więc wiele zdarzeń można wysłać na serwer, zanim aplikacja będzie mogła reagować, tworząc nowy render. Ma to pewne konsekwencje dla bezpieczeństwa, które należy wziąć pod uwagę. Ograniczanie akcji klienta w aplikacji musi być wykonywane wewnątrz procedur obsługi zdarzeń i nie zależy od bieżącego stanu widoku renderowanego.

Rozważ składnik licznika, który powinien umożliwić użytkownikowi zwiększanie licznika maksymalnie trzy razy. Przycisk zwiększający licznik jest warunkowo oparty na wartości count:

<p>Count: @count</p>

@if (count < 3)
{
    <button @onclick="IncrementCount" value="Increment count" />
}

@code 
{
    private int count = 0;

    private void IncrementCount()
    {
        count++;
    }
}

Klient może wysłać co najmniej jedno zdarzenie przyrostowe, zanim platforma utworzy nowy render tego składnika. W rezultacie użytkownik może zwiększyć countwięcej niż trzy razy, ponieważ przycisk nie jest usuwany przez UI wystarczająco szybko. Prawidłowy sposób osiągnięcia limitu trzech przyrostów count przedstawiono w poniższym przykładzie:

<p>Count: @count</p>

@if (count < 3)
{
    <button @onclick="IncrementCount" value="Increment count" />
}

@code 
{
    private int count = 0;

    private void IncrementCount()
    {
        if (count < 3)
        {
            count++;
        }
    }
}

Dodając if (count < 3) { ... } sprawdzenie wewnątrz programu obsługi, decyzja o zwiększeniu wartości count zależy od bieżącego stanu aplikacji. Decyzja nie jest oparta na stanie interfejsu użytkownika, tak jak w poprzednim przykładzie, co może być tymczasowo nieaktualne.

Ochrona przed wieloma wysyłkami

Jeśli funkcja zwrotna zdarzenia asynchronicznie uruchamia długotrwałą operację, taką jak pobieranie danych z zewnętrznej usługi lub bazy danych, rozważ zastosowanie mechanizmu zabezpieczającego. Mechanizm zabezpieczający może uniemożliwić użytkownikowi dodawanie wielu operacji do kolejki podczas trwania operacji, zapewniając wizualną informację zwrotną. Poniższy kod składnika ustawia wartość isLoading na true podczas DataService.GetDataAsync uzyskiwania danych z serwera. Gdy isLoading jest true, przycisk jest wyłączony w interfejsie użytkownika:

<button disabled="@isLoading" @onclick="UpdateData">Update</button>

@code {
    private bool isLoading;
    private Data[] data = Array.Empty<Data>();

    private async Task UpdateData()
    {
        if (!isLoading)
        {
            isLoading = true;
            data = await DataService.GetDataAsync(DateTime.Now);
            isLoading = false;
        }
    }
}

Wzorzec zabezpieczeń przedstawiony w poprzednim przykładzie działa, jeśli operacja w tle jest wykonywana asynchronicznie ze wzorcem async-await .

Anuluj wcześnie i unikaj użycia po usunięciu

Oprócz stosowania zabezpieczenia opisanego w sekcji Ochrona przed wieloma wysłaniami rozważ użycie elementu CancellationToken do anulowania długotrwałych operacji po usunięciu komponentu. Takie podejście ma dodatkową korzyść z unikania użycia po usunięciu składników:

@implements IDisposable

...

@code {
    private readonly CancellationTokenSource TokenSource = 
        new CancellationTokenSource();

    private async Task UpdateData()
    {
        ...

        data = await DataService.GetDataAsync(DateTime.Now, TokenSource.Token);

        if (TokenSource.Token.IsCancellationRequested)
        {
           return;
        }

        ...
    }

    public void Dispose()
    {
        TokenSource.Cancel();
    }
}

Unikaj zdarzeń, które generują duże ilości danych

Niektóre zdarzenia DOM, takie jak oninput lub onscroll, mogą generować dużą ilość danych. Unikaj używania tych zdarzeń na serwerze Blazor po stronie serwera.

Dodatkowe wskazówki dotyczące zabezpieczeń

Wskazówki dotyczące zabezpieczania aplikacji ASP.NET Core dotyczą aplikacji po stronie Blazor serwera i zostały omówione w poniższych sekcjach tego artykułu:

Rejestrowanie i poufne dane

JS interakcje interoperacyjne między klientem a serwerem są rejestrowane w dziennikach serwera jako wystąpienia ILogger. Blazor unika rejestrowania poufnych informacji, takich jak faktyczne zdarzenia lub JS dane wejściowe i wyjściowe interopu.

Gdy na serwerze wystąpi błąd, platforma powiadamia klienta i usuwa sesję. Klient otrzymuje ogólny komunikat o błędzie, który można zobaczyć w narzędziach deweloperskich przeglądarki.

Błąd po stronie klienta nie zawiera stosu wywołań i nie zawiera szczegółowych informacji na temat przyczyny błędu, ale dzienniki serwera zawierają takie informacje. Do celów programistycznych poufne informacje o błędach można udostępnić klientowi, włączając wyświetlanie szczegółowych informacji o błędach.

Ostrzeżenie

Ujawnienie informacji o błędach klientom w Internecie jest zagrożeniem bezpieczeństwa, którego należy zawsze unikać.

Ochrona informacji przesyłanych przy użyciu protokołu HTTPS

Blazor program używa SignalR do komunikacji między klientem a serwerem. Blazor zwykle używa transportu, który SignalR uzgadnia, a jest to zazwyczaj protokół WebSocket.

Blazor nie zapewnia integralności i poufności danych wysyłanych między serwerem a klientem. Zawsze używaj protokołu HTTPS.

Wykonywanie skryptów między witrynami (XSS)

Wykonywanie skryptów między witrynami (XSS) umożliwia nieautoryzowanej osobie wykonywanie dowolnej logiki w kontekście przeglądarki. Naruszona aplikacja może potencjalnie uruchamiać dowolny kod na kliencie. Luka w zabezpieczeniach może służyć do potencjalnie wykonywania wielu złośliwych akcji na serwerze:

  • Wysyłaj do serwera fałszywe lub nieprawidłowe zdarzenia.
  • Wysyłaj powiadomienia o zakończeniu nieudanego lub nieprawidłowego renderowania.
  • Unikaj wysyłania uzupełniania renderowania.
  • Wysyłanie wywołań międzyoperacyjnych z języka JavaScript do platformy .NET.
  • Zmodyfikuj odpowiedź wywołań międzyoperacyjnych z platformy .NET na język JavaScript.
  • Unikaj wysyłania platformy .NET do JS wyników międzyoperacji.

Platforma Blazor podejmuje kroki ochrony przed niektórymi poprzednimi zagrożeniami:

  • Przestaje generować nowe aktualizacje interfejsu użytkownika, jeśli klient nie potwierdza odbioru partii renderowania. Skonfigurowano za pomocą CircuitOptions.MaxBufferedUnacknowledgedRenderBatches.
  • Powoduje przekroczenie limitu czasu każdego wywołania z platformy .NET do języka JavaScript po upływie jednej minuty bez otrzymania odpowiedzi od klienta. Skonfigurowano za pomocą CircuitOptions.JSInteropDefaultCallTimeout.
  • Wykonuje podstawową walidację wszystkich danych wejściowych pochodzących z przeglądarki podczas interoperacyjności JS:
    • Referencje .NET są prawidłowe i mają typ oczekiwany przez metodę .NET.
    • Dane nie są nieprawidłowo sformatowane.
    • W ładunku danych znajduje się prawidłowa liczba argumentów metody.
    • Argumenty lub wynik mogą być poprawnie deserializowane przed wywołaniem metody.
  • Przeprowadza podstawową walidację we wszystkich danych wejściowych pochodzących z przeglądarki z wysłanych zdarzeń:
    • Zdarzenie ma prawidłowy typ.
    • Dane zdarzenia można deserializować.
    • Istnieje procedura obsługi zdarzeń skojarzona ze zdarzeniem.

Oprócz zabezpieczeń implementowanych przez platformę aplikacja musi być kodowana przez dewelopera, aby chronić przed zagrożeniami i podejmować odpowiednie działania:

  • Zawsze weryfikuj dane podczas obsługi zdarzeń.
  • Podejmij odpowiednie działania po otrzymaniu nieprawidłowych danych:
    • Ignoruj dane i wróć. Dzięki temu aplikacja może kontynuować przetwarzanie żądań.
    • Jeśli aplikacja ustali, że dane wejściowe są bezprawne i nie mogą być generowane przez uprawnionego klienta, należy zgłosić wyjątek. Wyrzucenie wyjątku powoduje zamknięcie obwodu i kończy sesję.
  • Nie ufaj komunikatowi o błędzie wyświetlanemu przez render batch completions w logach. Błąd jest dostarczany przez klienta i nie może być ogólnie zaufany, ponieważ klient może zostać naruszony.
  • Nie ufaj danym wejściowym w wywołaniach interoperacyjnych JS w obu kierunkach, między metodami JavaScript i .NET.
  • Aplikacja jest odpowiedzialna za weryfikowanie, czy zawartość argumentów i wyników jest prawidłowa, nawet jeśli argumenty lub wyniki są poprawnie deserializowane.

Aby luka w zabezpieczeniach XSS istniała, aplikacja musi uwzględniać dane wejściowe użytkownika na renderowanej stronie. Blazor wykonuje etap podczas kompilacji, w którym znaczniki w pliku .razor są przekształcane w proceduralną logikę w języku C#. W czasie wykonywania logika języka C# tworzy drzewo renderowania opisujące elementy, tekst i składniki podrzędne. Jest to stosowane do modelu DOM przeglądarki za pomocą sekwencji instrukcji języka JavaScript (lub jest serializowane do kodu HTML w przypadku prerenderingu):

  • Dane wejściowe użytkownika renderowane przy użyciu standardowej składni Razor (na przykład @someStringValue) nie powodują podatności na atak XSS, ponieważ składnia Razor jest dodawana do modelu DOM za pomocą poleceń, które mogą jedynie zapisywać tekst. Nawet jeśli wartość zawiera znacznik HTML, wartość jest wyświetlana jako tekst statyczny. Podczas prerenderingu dane wyjściowe są kodowane kodem HTML, który wyświetla również zawartość jako tekst statyczny.
  • Autorzy składników mogą tworzyć składniki w języku C# bez używania polecenia Razor. Autor składnika jest odpowiedzialny za używanie poprawnych interfejsów API podczas emitowania danych wyjściowych. Na przykład użyj builder.AddContent(0, someUserSuppliedString) i notbuilder.AddMarkupContent(0, someUserSuppliedString), ponieważ to drugie może spowodować podatność XSS.
  • Dane wejściowe użytkownika renderowane za pomocą zwykłej składni Razor (na przykład @someStringValue) nie powodują podatności na ataki XSS, ponieważ składnia Razor jest dodawana do drzewa DOM za pomocą poleceń, które mogą jedynie zapisywać tekst. Nawet jeśli wartość zawiera znacznik HTML, wartość jest wyświetlana jako tekst statyczny. Podczas prerenderingu dane wyjściowe są kodowane kodem HTML, który wyświetla również zawartość jako tekst statyczny.
  • Tagi skryptów nie są dozwolone i nie powinny być uwzględniane w drzewie renderowania składników aplikacji. Jeśli tag skryptu jest uwzględniony w znaczniku składnika, zostanie wygenerowany błąd czasu kompilacji.
  • Autorzy składników mogą tworzyć składniki w języku C# bez używania polecenia Razor. Autor składnika jest odpowiedzialny za używanie poprawnych interfejsów API podczas emitowania danych wyjściowych. Na przykład użyj builder.AddContent(0, someUserSuppliedString) i notbuilder.AddMarkupContent(0, someUserSuppliedString), ponieważ ta druga forma może spowodować powstanie luki w zabezpieczeniach typu XSS.

Rozważ dalsze ograniczenie luk w zabezpieczeniach XSS. Na przykład zaimplementuj restrykcyjne zasady zabezpieczeń zawartości (CSP). Aby uzyskać więcej informacji, zobacz Wymuszanie zasad zabezpieczeń zawartości dla ASP.NET Core Blazor i MDN CSP przewodnik.

Aby uzyskać więcej informacji, zobacz Zapobieganie skryptom między witrynami (XSS) w programie ASP.NET Core.

Ochrona między źródłami

Ataki obejmujące wiele źródeł obejmują klienta z innego źródła wykonującego akcję na serwerze. Złośliwe działanie jest zwykle żądaniem GET lub żądaniem POST wysyłanym z formularza (fałszowaniem żądań między witrynami, CSRF), ale możliwe jest również nawiązanie złośliwego połączenia WebSocket. Blazor aplikacje oferują takie same gwarancje jak każda inna SignalR aplikacja korzystająca z protokołu hub:

  • Dostęp do aplikacji z innych źródeł jest możliwy, o ile nie zostaną zastosowane dodatkowe środki zapobiegające temu. Aby wyłączyć dostęp między źródłami, wyłącz mechanizm CORS w punkcie końcowym, dodając składnik pośredniczący CORS do potoku i dodając element DisableCorsAttribute do metadanych punktu końcowego Blazor, albo ogranicz zestaw dozwolonych źródeł przez skonfigurowanie ustawienia SignalR dla mechanizmu Cross-Origin Resource Sharing. Aby uzyskać wskazówki dotyczące ograniczeń źródła protokołu WebSocket, zobacz Obsługa obiektów WebSocket w środowisku ASP.NET Core.
  • Jeśli mechanizm CORS jest włączony, może być wymagane wykonanie dodatkowych kroków w celu ochrony aplikacji w zależności od konfiguracji mechanizmu CORS. Jeśli mechanizm CORS jest włączony globalnie, można go wyłączyć dla centrum BlazorSignalR, dodając metadane DisableCorsAttribute do metadanych punktu końcowego po wywołaniu MapBlazorHub na obiekcie konstruktora tras punktu końcowego.

Aby uzyskać więcej informacji, zobacz Zapobieganie atakom polegającym na fałszowaniu żądań między witrynami (XSRF/CSRF) w aplikacjach ASP.NET Core.

Klikanie

Clickjacking polega na osadzeniu witryny jako elementu <iframe> w witrynie o innym pochodzeniu, w celu nakłonienia użytkownika do wykonania działań w atakowanej witrynie.

Aby chronić aplikację przed renderowaniem wewnątrz elementu <iframe>, użyj zasad zabezpieczeń zawartości (CSP) i nagłówka X-Frame-Options . Informacje o składni CSP znajdziesz w przewodniku MDN po CSP.

Aby uzyskać więcej informacji, zobacz następujące zasoby:

Otwieranie przekierowań

Po rozpoczęciu sesji aplikacji serwer przeprowadza podstawową walidację adresów URL wysłanych w ramach rozpoczynania sesji. Framework sprawdza, czy bazowy adres URL jest adresem nadrzędnym względem bieżącego adresu URL przed ustanowieniem obwodu. Framework nie wykonuje żadnych dodatkowych kontroli.

Gdy użytkownik wybierze link na kliencie, adres URL linku jest wysyłany do serwera, który określa, jakie działania należy podjąć. Na przykład aplikacja może wykonywać nawigację po stronie klienta lub wskazywać przeglądarce, aby przejść do nowej lokalizacji.

Składniki mogą również programowo wyzwalać żądania nawigacji za pomocą polecenia NavigationManager. W takich scenariuszach aplikacja może wykonywać nawigację po stronie klienta lub wskazywać przeglądarce, aby przejść do nowej lokalizacji.

Składniki muszą:

  • Unikaj używania danych wejściowych użytkownika w ramach argumentów wywołania nawigacji.
  • Sprawdź argumenty, aby upewnić się, że cel jest dozwolony w aplikacji.

W przeciwnym razie złośliwy użytkownik może wymusić przejście przeglądarki do witryny kontrolowanej przez cyberataki. W tym scenariuszu cyberatakujący nakłania aplikację do użycia części danych wejściowych użytkownika jako części wywołania metody NavigationManager.NavigateTo.

Ta porada ma zastosowanie również podczas renderowania linków w ramach aplikacji:

  • Jeśli to możliwe, użyj linków względnych.
  • Przed dołączeniem ich do strony sprawdź, czy bezwzględne lokalizacje docelowe linków są prawidłowe.

Aby uzyskać więcej informacji, zobacz Zapobieganie otwartym atakom przekierowania w programie ASP.NET Core.

Lista kontrolna zabezpieczeń

Poniższa lista zagadnień dotyczących zabezpieczeń nie jest kompleksowa:

  • Zweryfikuj argumenty ze zdarzeń.
  • Zweryfikuj dane wejściowe i wyniki wywołań interoperacyjnych JS.
  • Unikaj używania danych wejściowych użytkownika w wywołaniach interoperacyjnych platformy .NET do JS (lub wcześniej je zweryfikuj).
  • Uniemożliwia klientowi przydzielanie niezwiązanej ilości pamięci.
  • Ochrona przed wieloma wysyłkami.
  • Anuluj długotrwałe operacje, gdy składnik zostanie usunięty.
  • Unikaj zdarzeń, które generują duże ilości danych.
  • Należy unikać używania danych wejściowych użytkownika jako części wywołań do NavigationManager.NavigateTo, a jeśli nie da się tego uniknąć, najpierw należy zweryfikować dane wejściowe użytkownika pod kątem adresów URL względem zestawu dozwolonych źródeł.
  • Nie podejmuj decyzji dotyczących autoryzacji na podstawie stanu interfejsu użytkownika, ale tylko ze stanu składnika.
  • Rozważ użycie zasad zabezpieczeń zawartości (CSP) w celu ochrony przed atakami XSS. Aby uzyskać więcej informacji, zobacz Wymuszanie zasad zabezpieczeń zawartości dla ASP.NET Core Blazor i MDN CSP przewodnik.
  • Rozważ użycie mechanizmu CSP i X-Frame-Options, aby chronić przed atakami typu clickjacking.
  • Upewnij się, że ustawienia mechanizmu CORS są odpowiednie podczas włączania mechanizmu CORS lub jawnego wyłączania mechanizmu CORS dla Blazor aplikacji.
  • Przetestuj, aby upewnić się, że limity po stronie serwera dla Blazor aplikacji zapewniają akceptowalne środowisko użytkownika bez niedopuszczalnych poziomów ryzyka.