Udostępnij za pośrednictwem


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 bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

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 bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

W tym artykule wyjaśniono, jak ograniczyć zagrożenia bezpieczeństwa w interakcyjnej stronie Blazorserwera.

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 jako międzyoperacja języka JavaScript (JSmiędzyoperacja).

Ponieważ JS międzyoperacyjna odbywa się przez Internet, a klient korzysta z przeglądarki zdalnej, aplikacje współdzielą większość problemów z zabezpieczeniami aplikacji internetowych. 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 uwidocznić aplikację na ataki kanału bocznego na szyfrowanie TLS połączenia, takie jak CRIME ataki i BREACH ataki. Tego typu ataki wymagają, aby cyberataki:

  • Wymuszenie wysyłania żądań przez przeglądarkę z ładunkiem kontrolek cyberataków do witryny narażonej za pośrednictwem publikowania formularzy między witrynami lub osadzania witryny wewnątrz elementu iframe innej witryny.
  • Obserwuj długość skompresowanej i zaszyfrowanej odpowiedzi za pośrednictwem sieci.

Aby aplikacja była podatna na zagrożenia, musi odzwierciedlać ładunek z cyberataki w odpowiedzi, na przykład, pisząc ścieżkę lub ciąg zapytania do odpowiedzi. Korzystając z długości odpowiedzi, cyberatak może "odgadnąć" wszelkie informacje na temat odpowiedzi, przekazują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:

    • Po skonfigurowaniu Blazor kompresji automatycznie blokuje osadzanie aplikacji w ramce iframe, co blokuje początkową (nieskompresowaną) odpowiedź z serwera z renderowania i uniemożliwia rozpoczęcie połączenia Protokołu WebSocket.

    • 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ę, jak Blazor renderuje (renderuje raz, a następnie tworzy różnice zawartości tylko dla zmienionych elementów), trudno jest to osiągnąć cyberatak. 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:

    • Renderuj dane osobowe (PII) na stronie w tym samym czasie co renderowanie danych bazy danych, które zostały dodane przez innego użytkownika.

    • Renderowanie informacji osobowych na stronie w tym samym czasie co dane pochodzące z innego użytkownika za pośrednictwem JS międzyoperacyjnej lub lokalnej usługi pojedynczej 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, ciągi zapytań, dane z JS międzyoperacyjności i inne źródło danych, które użytkownik innej firmy może kontrolować (bazy danych, usługi zewnętrzne).

Stan udostępniony

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 Blazor aplikacji rozpoczyna obwód z własnym zakresem kontenera wstrzykiwania zależności, w związku z czym usługi o określonym zakresie są unikatowe dla Blazor sesji.

Ostrzeżenie

Nie zalecamy, aby aplikacje na tym samym serwerze miały stan udostępniania przy użyciu usług singleton, chyba że zostanie podjęta skrajna ostrożność, ponieważ może to powodować luki w zabezpieczeniach, takie jak wyciek stanu użytkownika między obwodami.

Możesz używać stanowych pojedynczych usług w Blazor aplikacjach, jeśli zostały one specjalnie zaprojektowane. Na przykład użycie pojedynczej pamięci podręcznej jest dopuszczalne, ponieważ pamięć podręczna pamięci wymaga klucza dostępu 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 Blazor ASP.NET Core.

IHttpContextAccessor/HttpContext

IHttpContextAccessor powinno się zazwyczaj unikać w połączeniu z renderowaniem interaktywnym, ponieważ prawidłowe HttpContext nie zawsze jest dostępne.

IHttpContextAccessor Może służyć do składników, które są statycznie renderowane na serwerze. Zalecamy jednak unikanie go, jeśli to możliwe.

HttpContextMoże być używany jako parametr kaskadowy tylko w statycznie renderowanych składnikach głównych dla zadań ogólnych, takich jak inspekcja i modyfikowanie nagłówków lub innych właściwości w składniku App (Components/App.razor). Wartość jest zawsze null dla renderowania interakcyjnego.

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

W przypadku scenariuszy, w których HttpContext element jest wymagany w składnikach interaktywnych, zalecamy przepływ danych za pośrednictwem stanu trwałego składnika z serwera. Aby uzyskać więcej informacji, zobacz scenariusze ASP.NET Core po stronie serwera i Blazor Web App dodatkowe scenariusze zabezpieczeń.

Nie używaj IHttpContextAccessor/HttpContext bezpośrednio ani pośrednio składników Razor aplikacji po stronie Blazor serwera. Blazor aplikacje działają poza kontekstem potoku ASP.NET Core. Nie HttpContext ma gwarancji, że element jest dostępny w programie IHttpContextAccessori HttpContext nie ma gwarancji, że przechowuje kontekst, w ramach którego uruchomiono aplikację Blazor .

Zalecaną metodą przekazywania stanu żądania do Blazor aplikacji są parametry składnika głównego podczas początkowego renderowania aplikacji. Alternatywnie aplikacja może skopiować dane do usługi o określonym zakresie w zdarzeniu cyklu życia inicjowania składnika głównego do użycia w całej aplikacji. Aby uzyskać więcej informacji, zobacz scenariusze ASP.NET Core po stronie serwera i Blazor Web App dodatkowe scenariusze zabezpieczeń.

Krytycznym aspektem zabezpieczeń po stronie Blazor serwera jest to, że użytkownik dołączony do danego obwodu może zostać zaktualizowany w pewnym momencie po ustanowieniu obwoduBlazor, ale IHttpContextAccessornie został zaktualizowany. Aby uzyskać więcej informacji na temat rozwiązywania tej sytuacji z usługami niestandardowymi, zobacz ASP.NET Podstawowe scenariusze zabezpieczeń i Blazor Web App dodatkowe scenariusze zabezpieczeń.

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 poza strukturą Blazor , takie jak bazy danych i dojścia plików (używane do odczytu i zapisu plików), mogą również wystąpić wyczerpanie zasobów. Aby uzyskać więcej informacji, zobacz ASP.NET Core Best Practices (Najlepsze rozwiązania podstawowe).

Procesor 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ść.

Wyczerpanie procesora CPU jest problemem dla wszystkich aplikacji publicznych. W zwykłych aplikacjach internetowych limit czasu żądań i połączeń jest przekroczony jako zabezpieczenie, ale Blazor aplikacje nie zapewniają tych samych zabezpieczeń. Blazor aplikacje muszą uwzględniać odpowiednie kontrole i limity przed wykonaniem potencjalnie intensywnej pracy procesora CPU.

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 momentu 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 List<T> właściwości lub polu używają pamięci serwera. Jeśli aplikacja zezwala na zwiększanie liczby elementów bez ruchu, istnieje ryzyko, że serwer zabraknie pamięci. Brak pamięci powoduje zakończenie bieżącej sesji (awaria) i 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ść:
    • Podczas renderowania użyj list podzielonych na strony.
    • 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. Niedysponowanych elementów można również przechowywać w pamięci, co jest mniej idealne.

Uwaga

Blazor ma wbudowaną obsługę wirtualizacji. Aby uzyskać więcej informacji, zobacz Razor składników podstawowego systemu ASP.NET Core).

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 po stronie Blazor serwera pamięć zużywana przez aplikację należy do serwera i jest współdzielona między klientami w wystąpieniu 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 programowania profiler może być używany lub przechwytywany ślad w celu oceny zapotrzebowania klientów na pamięć. Profiler lub ślad nie przechwytuje pamięci przydzielonej do określonego klienta. Aby przechwycić użycie pamięci określonego klienta podczas programowania, przechwyć zrzut i zbadać zapotrzebowanie na pamięć wszystkich obiektów zakorzenionych w obwodzie 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, użytkownicy muszą uniemożliwić 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).
  • Wymagaj uwierzytelniania, co naturalnie ogranicza możliwość nieautoryzowanego łączenia użytkowników z aplikacją. Aby ten scenariusz był skuteczny, użytkownicy muszą uniemożliwić 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 uwierzytelniania, aby nawiązać połączenie z aplikacją i śledzić aktywne sesje na użytkownika.
      • Odrzuć nowe sesje po osiągnięciu limitu.
      • Proxy WebSocket połączenia z aplikacją za pośrednictwem serwera proxy, takiego jak SignalR platformy Azure, która 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 przed aplikacją.
      • Chociaż długie sondowanie jest obsługiwane w Blazor przypadku aplikacji, protokół WebSocket jest zalecanym protokołem transportu. Zalecamy wybranie serwera proxy/bramy obsługującego obiekty WebSocket.

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 obejmują domyślne limity i polegają na innych ASP.NET Core i SignalR limitach, które są ustawione 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 współdziała z serwerem za pośrednictwem JS wysyłania i renderowania zdarzeń międzyoperacyjności. 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 reaguje asynchronicznie rerendering interfejsu użytkownika w razie potrzeby.

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ć:
    • Przyczyna problemu w aplikacji przez zwrócenie błędu z funkcji JavaScript.
    • Wywołanie niezamierzonego zachowania na serwerze przez zwrócenie nieoczekiwanego wyniku z funkcji JavaScript.

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

  • Zawijaj JS wywołania międzyoperacyjne w instrukcjach try-catch , aby uwzględnić błędy, które mogą wystąpić podczas wywołań. Aby uzyskać więcej informacji, zobacz 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 uwidoczniona w języku JavaScript, rozważ wywołanie metody .NET:

  • Traktuj dowolną metodę platformy .NET uwidacznianą w języku JavaScript, tak 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ć ustanawiania stanu, którego nie można ograniczyć do klienta, chyba że aplikacja jawnie współużytkuje stan według projektu dla wszystkich użytkowników w wystąpieniu 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.
  • Unikaj implementowania niestandardowego wysyłania wywołań platformy .NET na podstawie implementacji wysyłania platformy. 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 wysyłać wszelkie dane, które chce wysłać jako ładunek zdarzenia.

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ę. Składniki Blazor formularzy platformy wykonują podstawowe walidacje. 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. Wynikiem jest to, że count element może być zwiększany przez użytkownika ponad trzy razy, ponieważ przycisk nie jest usuwany przez interfejs użytkownika wystarczająco szybko. Prawidłowym sposobem osiągnięcia limitu trzech count przyrostów jest pokazany 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++;
        }
    }
}

if (count < 3) { ... } Dodając sprawdzanie wewnątrz procedury obsługi, decyzja o przyrostie 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 wywołanie zwrotne zdarzeń wywołuje długotrwałą operację asynchronicznie, taką jak pobieranie danych z zewnętrznej usługi lub bazy danych, rozważ użycie zabezpieczenia. Zabezpieczenie może uniemożliwić użytkownikowi kolejkowanie wielu operacji, gdy operacja jest w toku z opiniami wizualnymi. Poniższy kod składnika ustawia wartość isLoading na true podczas DataService.GetDataAsync uzyskiwania danych z serwera. Gdy isLoading element to 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 używania zabezpieczeń zgodnie z opisem w sekcji Ochrona przed wieloma wysyłkami rozważ użycie elementu , CancellationToken aby anulować długotrwałe operacje po usunięciu składnika. 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 po stronie Blazor 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 międzyoperacyjności między klientem a serwerem są rejestrowane w dziennikach serwera z ILogger wystąpieniami. Blazor pozwala uniknąć rejestrowania poufnych informacji, takich jak rzeczywiste zdarzenia lub JS dane wejściowe i wyjściowe międzyoperacyjności.

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. W celach programistycznych poufne informacje o błędach można udostępnić klientowi, włączając szczegółowe błędy.

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 negocjuje, czyli zazwyczaj obiektów 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łanie fałszywych/nieprawidłowych zdarzeń do serwera.
  • Wysyłanie zakończonych niepowodzeniem/nieprawidłowym renderowaniem.
  • 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:

  • Zatrzymuje tworzenie nowych aktualizacji interfejsu użytkownika, jeśli klient nie uznaje partii renderowania. Skonfigurowano za pomocą polecenia CircuitOptions.MaxBufferedUnacknowledgedRenderBatches.
  • Limit czasu wywołania platformy .NET do języka JavaScript po jednej minucie bez otrzymania odpowiedzi od klienta. Skonfigurowano za pomocą polecenia CircuitOptions.JSInteropDefaultCallTimeout.
  • Przeprowadza podstawową walidację wszystkich danych wejściowych pochodzących z przeglądarki podczas JS międzyoperacyjności:
    • Odwołania platformy .NET są prawidłowe i typu oczekiwanego przez metodę .NET.
    • Dane nie są źle sformułowane.
    • Prawidłowa liczba argumentów metody znajduje się w ładunku.
    • 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 mogą być deserializowane.
    • 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 zwracaj. 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. Zgłaszanie wyjątku usuwa obwód i kończy sesję.
  • Nie ufaj komunikatowi o błędzie dostarczonemu przez renderowanie uzupełniania partii zawartego w dziennikach. Błąd jest dostarczany przez klienta i nie może być ogólnie zaufany, ponieważ klient może zostać naruszony.
  • Nie ufaj wejściom w JS wywołaniach międzyoperacyjnych 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 krok czasu kompilacji, w którym znaczniki w .razor pliku są przekształcane w proceduralną logikę języka 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 za pomocą składni normalnej Razor (na przykład ) nie uwidacznia luki w zabezpieczeniach XSS, @someStringValueponieważ składnia Razor jest dodawana do modelu DOM za pomocą poleceń, które mogą pisać tylko 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 należy użyć elementu builder.AddContent(0, someUserSuppliedString) ,builder.AddMarkupContent(0, someUserSuppliedString)ponieważ ten ostatni może utworzyć lukę w zabezpieczeniach XSS.
  • Dane wejściowe użytkownika renderowane za pomocą składni normalnej Razor (na przykład ) nie uwidacznia luki w zabezpieczeniach XSS, @someStringValueponieważ składnia Razor jest dodawana do modelu DOM za pomocą poleceń, które mogą pisać tylko 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 należy użyć elementu builder.AddContent(0, someUserSuppliedString) ,builder.AddMarkupContent(0, someUserSuppliedString)ponieważ ten ostatni może utworzyć lukę w zabezpieczeniach 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.

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śliwa akcja jest zazwyczaj żądaniem GET lub formularzem POST (fałszerzowanym żądaniem między witrynami, CSRF), ale otwarcie złośliwego protokołu WebSocket jest również możliwe. Blazor aplikacje oferują te same gwarancje, że każda inna SignalR aplikacja korzystająca z oferty protokołu hub:

  • Dostęp do aplikacji między źródłami można uzyskać, chyba że zostaną podjęte dodatkowe środki, aby temu zapobiec. Aby wyłączyć dostęp między źródłami, wyłącz mechanizm CORS w punkcie końcowym przez dodanie oprogramowania pośredniczącego CORS do potoku i dodanie DisableCorsAttribute elementu do Blazor metadanych punktu końcowego lub ograniczenie zestawu dozwolonych źródeł przez skonfigurowanie funkcji współużytkowania SignalRzasobów między źródłami. 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, mechanizm CORS można wyłączyć dla BlazorSignalR centrum, dodając DisableCorsAttribute metadane do metadanych punktu końcowego po wywołaniu MapBlazorHub w konstruktorze tras punktu końcowego.

Aby uzyskać więcej informacji, zobacz Zapobieganie atakom z fałszowaniem żądań międzywitrynowych (XSRF/CSRF) na platformie ASP.NET Core.

Klikanie

Klikanie polega na renderowaniu witryny jako <iframe> wewnątrz witryny z innego źródła, aby skłonić użytkownika do wykonywania akcji w witrynie w ramach ataku.

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

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. Platforma sprawdza, czy podstawowy adres URL jest elementem nadrzędnym bieżącego adresu URL przed ustanowieniem obwodu. Żadne dodatkowe kontrole nie są wykonywane przez platformę.

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.
  • Zweryfikuj argumenty, aby upewnić się, że element docelowy jest dozwolony przez aplikację.

W przeciwnym razie złośliwy użytkownik może wymusić przejście przeglądarki do witryny kontrolowanej przez cyberataki. W tym scenariuszu cyberattacker wykorzystuje aplikację do używania niektórych danych wejściowych NavigationManager.NavigateTo użytkownika w ramach wywołania metody.

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 z JS wywołań międzyoperacyjnych.
  • Unikaj używania (lub weryfikowania wcześniej) danych wejściowych użytkownika dla platformy .NET do JS wywołań międzyoperacyjnych.
  • 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 w ramach wywołań i weryfikować NavigationManager.NavigateTo dane wejściowe użytkownika pod kątem adresów URL dla zestawu dozwolonych źródeł, jeśli jest to nieuniknione.
  • 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.
  • Rozważ użycie opcji CSP i X-Frame-Options , aby chronić przed kliknięciem.
  • 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.