Безопасные ASP.NET Core Blazor серверные приложенияSecure ASP.NET Core Blazor Server apps

Хавьер Калварро ВоронковBy Javier Calvarro Nelson

Blazor серверные приложения принимают модель обработки данных с отслеживанием состояния , где сервер и клиент поддерживают долгосрочную связь. Server apps adopt a stateful data processing model, where the server and client maintain a long-lived relationship. Постоянное состояние поддерживается каналом, который может охватывать соединения, которые также потенциально долго исключаются.The persistent state is maintained by a circuit, which can span connections that are also potentially long-lived.

Когда пользователь посещает сайт Blazor Server, сервер создает канал в памяти сервера.When a user visits a Blazor Server site, the server creates a circuit in the server's memory. Канал указывает браузеру, какое содержимое подготавливается к просмотру, и реагирует на события, например, когда пользователь выбирает кнопку в пользовательском интерфейсе.The circuit indicates to the browser what content to render and responds to events, such as when the user selects a button in the UI. Для выполнения этих действий цепь вызывает функции JavaScript в браузере пользователя и методах .NET на сервере.To perform these actions, a circuit invokes JavaScript functions in the user's browser and .NET methods on the server. Это двустороннее взаимодействие на основе JavaScript называется взаимодействием JavaScript (JS Interop).This two-way JavaScript-based interaction is referred to as JavaScript interop (JS interop).

Поскольку взаимодействие с JS происходит через Интернет, а клиент использует удаленный браузер, Blazor серверные приложения используют большинство проблем безопасности веб-приложений.Because JS interop occurs over the Internet and the client uses a remote browser, Blazor Server apps share most web app security concerns. В этом разделе описываются распространенные угрозы для Blazor серверных приложений и предоставляются рекомендации по предотвращению угроз, направленные на приложения с выходом в Интернет.This topic describes common threats to Blazor Server apps and provides threat mitigation guidance focused on Internet-facing apps.

В ограниченных средах, например в корпоративных сетях или интрасетях, некоторые рекомендации по устранению рисков:In constrained environments, such as inside corporate networks or intranets, some of the mitigation guidance either:

  • Не применяется в ограниченной среде.Doesn't apply in the constrained environment.
  • Не стоит тратить затраты на реализацию, так как в ограниченной среде существует угроза безопасности.Isn't worth the cost to implement because the security risk is low in a constrained environment.

Нехватка ресурсовResource exhaustion

Нехватка ресурсов может произойти, когда клиент взаимодействует с сервером и заставляет сервер потреблять чрезмерные ресурсы.Resource exhaustion can occur when a client interacts with the server and causes the server to consume excessive resources. Чрезмерное потребление ресурсов в основном влияет на:Excessive resource consumption primarily affects:

Атаки типа "отказ в обслуживании" (DoS) обычно ищут исчерпание ресурсов приложения или сервера.Denial of service (DoS) attacks usually seek to exhaust an app or server's resources. Однако нехватка ресурсов не обязательно является результатом атаки на систему.However, resource exhaustion isn't necessarily the result of an attack on the system. Например, ограниченные ресурсы могут быть исчерпаны из-за высокой потребности пользователей.For example, finite resources can be exhausted due to high user demand. DoS рассматривается в разделе атаки типа "отказ в обслуживании" (DOS) .DoS is covered further in the Denial of service (DoS) attacks section.

Ресурсы, внешние по отношению к Blazor Framework, такие как базы данных и дескрипторы файлов (используемые для чтения и записи файлов), могут также испытывать нехватку ресурсов.Resources external to the Blazor framework, such as databases and file handles (used to read and write files), may also experience resource exhaustion. Для получения дополнительной информации см. Рекомендации по повышению производительности ASP.NET Core.For more information, see Рекомендации по повышению производительности ASP.NET Core.

ЦПCPU

Нехватка ресурсов ЦП может возникать, когда один или несколько клиентов вынуждены заставить сервер выполнять интенсивную работу ЦП.CPU exhaustion can occur when one or more clients force the server to perform intensive CPU work.

Например, рассмотрим Blazor серверное приложение, которое вычисляет номер фибоннакЦи.For example, consider a Blazor Server app that calculates a Fibonnacci number. Номер ФибоннакЦи создается из последовательности ФибоннакЦи, где каждое число в последовательности является суммой двух предыдущих чисел.A Fibonnacci number is produced from a Fibonnacci sequence, where each number in the sequence is the sum of the two preceding numbers. Объем работы, необходимый для достижения ответа, зависит от длины последовательности и размера начального значения.The amount of work required to reach the answer depends on the length of the sequence and the size of the initial value. Если приложение не помещает ограничения на клиентский запрос, вычисления с интенсивным использованием ЦП могут повлиять на время ЦП и уменьшить производительность других задач.If the app doesn't place limits on a client's request, the CPU-intensive calculations may dominate the CPU's time and diminish the performance of other tasks. Чрезмерное потребление ресурсов является проблемой безопасности, влияющей на доступность.Excessive resource consumption is a security concern impacting availability.

Нехватка ресурсов ЦП очень важна для всех общедоступных приложений.CPU exhaustion is a concern for all public-facing apps. В обычных веб-приложениях время ожидания запросов и соединений является защитой, но Blazor серверные приложения не предоставляют одинаковые меры безопасности.In regular web apps, requests and connections time out as a safeguard, but Blazor Server apps don't provide the same safeguards. приложения Blazor Server должны включать соответствующие проверки и ограничения перед выполнением потенциально требовательных к ЦП операций.Blazor Server apps must include appropriate checks and limits before performing potentially CPU-intensive work.

ПамятьMemory

Нехватка памяти может произойти, когда один или несколько клиентов вынуждены принудительно использовать большой объем памяти.Memory exhaustion can occur when one or more clients force the server to consume a large amount of memory.

Например, рассмотрим Blazorприложение на стороне сервера с компонентом, который принимает и отображает список элементов.For example, consider a Blazor-server side app with a component that accepts and displays a list of items. Если Blazorное приложение не устанавливает ограничения на количество разрешенных элементов или число элементов, отображаемых обратно клиенту, обработка и отрисовка с интенсивным использованием памяти может налагаться на то, что производительность сервера снижается.If the Blazor app doesn't place limits on the number of items allowed or the number of items rendered back to the client, the memory-intensive processing and rendering may dominate the server's memory to the point where performance of the server suffers. Сервер может аварийно завершить работу или замедляться до момента сбоя.The server may crash or slow to the point that it appears to have crashed.

Рассмотрим следующий сценарий для обслуживания и отображения списка элементов, относящихся к потенциальному сценарию нехватки памяти на сервере:Consider the following scenario for maintaining and displaying a list of items that pertain to a potential memory exhaustion scenario on the server:

  • Элементы в свойстве или поле List<MyItem> используют память сервера.The items in a List<MyItem> property or field use the server's memory. Если приложение разрешает неограниченный рост списка элементов, существует риск нехватки памяти на сервере.If the app allows the list of items to grow unbounded, there's a risk of the server running out of memory. При нехватке памяти текущий сеанс завершается (со сбоем) и все параллельные сеансы в этом экземпляре сервера получают исключение нехватки памяти.Running out of memory causes the current session to end (crash) and all of the concurrent sessions in that server instance receive an out-of-memory exception. Чтобы предотвратить возникновение этого сценария, приложение должно использовать структуру данных, которая накладывает ограничение на число элементов для параллельных пользователей.To prevent this scenario from occurring, the app must use a data structure that imposes an item limit on concurrent users.
  • Если схема подкачки не используется для отрисовки, сервер использует дополнительную память для объектов, которые не видны в пользовательском интерфейсе.If a paging scheme isn't used for rendering, the server uses additional memory for objects that aren't visible in the UI. Без ограничения на количество элементов требования к памяти могут привести к исчерпанию доступной памяти сервера.Without a limit on the number of items, memory demands may exhaust the available server memory. Чтобы предотвратить такой сценарий, используйте один из следующих подходов:To prevent this scenario, use one of the following approaches:
    • Используйте списки с разбивкой на страницы при подготовке к просмотру.Use paginated lists when rendering.
    • Отображать только первые 100 – 1 000 элементов и требовать от пользователя ввести условия поиска для поиска элементов за пределами отображаемых элементов.Only display the first 100 to 1,000 items and require the user to enter search criteria to find items beyond the items displayed.
    • Для более расширенного сценария подготовки к просмотру реализуйте списки или сетки, поддерживающие виртуализацию.For a more advanced rendering scenario, implement lists or grids that support virtualization. С помощью виртуализации в списках отображаются только подмножество элементов, видимых пользователю.Using virtualization, lists only render a subset of items currently visible to the user. Когда пользователь взаимодействует с полосой прокрутки в пользовательском интерфейсе, компонент отображает только те элементы, которые требуются для отображения.When the user interacts with the scrollbar in the UI, the component renders only those items required for display. Элементы, которые в данный момент не требуются для вывода, могут храниться во вторичном хранилище, что является идеальным подходом.The items that aren't currently required for display can be held in secondary storage, which is the ideal approach. Неотображаемые элементы также могут храниться в памяти, что является менее идеальным.Undisplayed items can also be held in memory, which is less ideal.

Blazor серверные приложения предлагают аналогичную модель программирования для других платформ пользовательского интерфейса для приложений с отслеживанием состояния, таких как WPF, Windows Forms или Blazor сборки. Server apps offer a similar programming model to other UI frameworks for stateful apps, such as WPF, Windows Forms, or Blazor WebAssembly. Основное отличие состоит в том, что в некоторых платформах пользовательского интерфейса объем памяти, потребляемой приложением, принадлежит клиенту и влияет только на этот клиент.The main difference is that in several of the UI frameworks the memory consumed by the app belongs to the client and only affects that individual client. Например, Blazor приложение сборки выполняется на клиенте полностью и использует только ресурсы памяти клиента.For example, a Blazor WebAssembly app runs entirely on the client and only uses client memory resources. В сценарии Blazor Server память, потребляемая приложением, принадлежит серверу и является общей для клиентов на экземпляре сервера.In the Blazor Server scenario, the memory consumed by the app belongs to the server and is shared among clients on the server instance.

Требования к памяти на стороне сервера учитываются для всех Blazor серверных приложений.Server-side memory demands are a consideration for all Blazor Server apps. Однако большинство веб-приложений не имеют состояния, и память, используемая при обработке запроса, освобождается при возврате ответа.However, most web apps are stateless, and the memory used while processing a request is released when the response is returned. В качестве общей рекомендации не разрешите клиентам выделять неограниченный объем памяти, как в любом другом серверном приложении, сохраняющем клиентские подключения.As a general recommendation, don't permit clients to allocate an unbound amount of memory as in any other server-side app that persists client connections. Объем памяти, потребляемой приложением Blazor Server, сохраняется дольше одного запроса.The memory consumed by a Blazor Server app persists for a longer time than a single request.

Примечание

Во время разработки можно использовать профилировщик или трассировку, отслеживаемую для оценки требований к памяти клиентов.During development, a profiler can be used or a trace captured to assess memory demands of clients. Профилировщик или трассировка не захватывает память, выделенную для конкретного клиента.A profiler or trace won't capture the memory allocated to a specific client. Чтобы записать использование памяти конкретным клиентом во время разработки, запишите дамп и изучите потребность в памяти для всех объектов, имеющих корень в цепи пользователя.To capture the memory use of a specific client during development, capture a dump and examine the memory demand of all the objects rooted at a user's circuit.

Подключения клиентовClient connections

Нехватка подключений может возникать, когда один или несколько клиентов открывают слишком много одновременных подключений к серверу, предотвращая установку новых подключений другими клиентами.Connection exhaustion can occur when one or more clients open too many concurrent connections to the server, preventing other clients from establishing new connections.

Blazor клиенты устанавливают одно подключение для каждого сеанса и сохраняют подключение открытым до тех пор, пока открыто окно браузера. clients establish a single connection per session and keep the connection open for as long as the browser window is open. Требования к серверу для обслуживания всех подключений не относятся к Blazorным приложениям.The demands on the server of maintaining all of the connections isn't specific to Blazor apps. Учитывая постоянную природу подключений и характерность Blazor серверных приложений, нехватка подключений повышает риск доступности приложения.Given the persistent nature of the connections and the stateful nature of Blazor Server apps, connection exhaustion is a greater risk to availability of the app.

По умолчанию количество подключений на одного пользователя для Blazor серверного приложения не ограничено.By default, there's no limit on the number of connections per user for a Blazor Server app. Если для приложения требуется ограничение числа подключений, воспользуйтесь одним или несколькими из следующих подходов.If the app requires a connection limit, take one or more of the following approaches:

  • Требовать проверку подлинности, которая естественным образом ограничивает возможность неавторизованных пользователей подключаться к приложению.Require authentication, which naturally limits the ability of unauthorized users to connect to the app. Чтобы этот сценарий действовал, пользователи должны быть предотвращены от подготовки новых пользователей.For this scenario to be effective, users must be prevented from provisioning new users at will.
  • Ограничьте число подключений на пользователя.Limit the number of connections per user. Ограничение подключений можно выполнить с помощью следующих подходов.Limiting connections can be accomplished via the following approaches. Примите во внимание, чтобы предоставить законным пользователям доступ к приложению (например, если установлено ограничение на число подключений на основе IP-адреса клиента).Exercise care to allow legitimate users to access the app (for example, when a connection limit is established based on the client's IP address).
    • На уровне приложения:At the app level:
      • Расширяемость маршрутизации конечных точек.Endpoint routing extensibility.
      • Требовать проверку подлинности для подключения к приложению и наблюдения за активными сеансами на пользователя.Require authentication to connect to the app and keep track of the active sessions per user.
      • Отклоните новые сеансы при достижении предела.Reject new sessions upon reaching a limit.
      • Прокси-подключения WebSocket к приложению с помощью прокси-сервера, например службы SignalR Azure , которая мультиплексует подключения от клиентов к приложению.Proxy WebSocket connections to an app through the use of a proxy, such as the Azure SignalR Service that multiplexes connections from clients to an app. Это предоставляет приложению более высокую емкость подключения, чем может установить один клиент, что предотвращает исчерпание подключений клиента к серверу.This provides an app with greater connection capacity than a single client can establish, preventing a client from exhausting the connections to the server.
    • На уровне сервера: Используйте прокси-сервер или шлюз перед приложением.At the server level: Use a proxy/gateway in front of the app. Например, Передняя дверца Azure позволяет определять и отслеживать глобальную маршрутизацию веб-трафика в приложение, а также управлять им.For example, Azure Front Door enables you to define, manage, and monitor the global routing of web traffic to an app.

Атаки типа "отказ в обслуживании" (DoS)Denial of service (DoS) attacks

Атаки типа "отказ в обслуживании" (DoS) подразумевают, что клиент выводит на сервер недоступность одного или нескольких ресурсов из-за того, что приложение не будет доступно.Denial of service (DoS) attacks involve a client causing the server to exhaust one or more of its resources making the app unavailable. Blazor серверные приложения включают некоторые ограничения по умолчанию и полагаются на другие ограничения ASP.NET Core и SignalR для защиты от атак DoS. Server apps include some default limits and rely on other ASP.NET Core and SignalR limits to protect against DoS attacks:

ограничение серверного приложения BlazorBlazor Server app limit ОписаниеDescription Значение по умолчаниюDefault
CircuitOptions.DisconnectedCircuitMaxRetained Максимальное число отключенных каналов, которые заданный сервер удерживает в памяти за один раз.Maximum number of disconnected circuits that a given server holds in memory at a time. 100100
CircuitOptions.DisconnectedCircuitRetentionPeriod Максимальное время, в течение которого отключенная цепь удерживается в памяти, прежде чем будет прервана.Maximum amount of time a disconnected circuit is held in memory before being torn down. 3 минуты3 minutes
CircuitOptions.JSInteropDefaultCallTimeout Максимальное время ожидания сервера до истечения времени ожидания асинхронного вызова функции JavaScript.Maximum amount of time the server waits before timing out an asynchronous JavaScript function invocation. 1 минута1 minute
CircuitOptions.MaxBufferedUnacknowledgedRenderBatches Максимальное число неподтвержденных пакетов рендеринга, которые сервер хранит в памяти на канал в указанное время для поддержки надежного повторного подключения.Maximum number of unacknowledged render batches the server keeps in memory per circuit at a given time to support robust reconnection. После достижения предела сервер прекращает создавать новые пакеты рендеринга, пока один или несколько пакетов не будут подтверждены клиентом.After reaching the limit, the server stops producing new render batches until one or more batches have been acknowledged by the client. 1010
ограничение SignalR и ASP.NET CoreSignalR and ASP.NET Core limit ОписаниеDescription Значение по умолчаниюDefault
CircuitOptions.MaximumReceiveMessageSize Размер сообщения для отдельного сообщения.Message size for an individual message. 32 КБ32 KB

Взаимодействие с браузером (клиент)Interactions with the browser (client)

Клиент взаимодействует с сервером через JS-событие взаимодействия и завершение отрисовки.A client interacts with the server through JS interop event dispatching and render completion. Взаимодействие между JavaScript и .NET осуществляется в обоих направлениях:JS interop communication goes both ways between JavaScript and .NET:

  • События браузера отправляются с клиента на сервер асинхронным образом.Browser events are dispatched from the client to the server in an asynchronous fashion.
  • Сервер отвечает асинхронно, при необходимости, перерисовывает пользовательский интерфейс.The server responds asynchronously rerendering the UI as necessary.

Функции JavaScript, вызываемые из .NETJavaScript functions invoked from .NET

Для вызовов из методов .NET к JavaScript:For calls from .NET methods to JavaScript:

  • Все вызовы имеют настраиваемое время ожидания, после которого они завершаются сбоем, возвращая OperationCanceledException вызывающему.All invocations have a configurable timeout after which they fail, returning a OperationCanceledException to the caller.
    • Время ожидания вызовов (CircuitOptions.JSInteropDefaultCallTimeout) по умолчанию — одна минута.There's a default timeout for the calls (CircuitOptions.JSInteropDefaultCallTimeout) of one minute. Чтобы настроить это ограничение, см. раздел ASP.NET Core Blazor взаимодействия JavaScript.To configure this limit, see ASP.NET Core Blazor взаимодействия JavaScript.
    • Для управления отменой на основе каждого вызова можно предоставить токен отмены.A cancellation token can be provided to control the cancellation on a per-call basis. Полагаться на время ожидания вызова по умолчанию, когда это возможно, и с ограниченным временем любым вызовом клиента, если предоставлен токен отмены.Rely on the default call timeout where possible and time-bound any call to the client if a cancellation token is provided.
  • Результат вызова JavaScript не может быть доверенным.The result of a JavaScript call can't be trusted. Клиент Blazor приложения, запущенный в браузере, выполняет поиск вызываемой функции JavaScript.The Blazor app client running in the browser searches for the JavaScript function to invoke. Вызывается функция и создается либо результат, либо ошибка.The function is invoked, and either the result or an error is produced. Вредоносный клиент может попытаться:A malicious client can attempt to:
    • Вызывает проблемы в приложении, возвращая ошибку из функции JavaScript.Cause an issue in the app by returning an error from the JavaScript function.
    • Вызывает непреднамеренное поведение сервера, возвращая непредвиденный результат из функции JavaScript.Induce an unintended behavior on the server by returning an unexpected result from the JavaScript function.

Примите следующие меры предосторожности, чтобы защититься от предыдущих сценариев.Take the following precautions to guard against the preceding scenarios:

  • Заключите вызовы взаимодействия JS внутри операторов try-catch , чтобы учитывать ошибки, которые могут возникнуть во время вызовов.Wrap JS interop calls within try-catch statements to account for errors that might occur during the invocations. Для получения дополнительной информации см. Обработку ошибок в приложениях ASP.NET Core Blazor.For more information, see Обработку ошибок в приложениях ASP.NET Core Blazor.
  • Перед выполнением каких бы то ни было действий проверьте данные, возвращаемые при вызовах взаимодействия с JS, включая сообщения об ошибках.Validate data returned from JS interop invocations, including error messages, before taking any action.

Методы .NET, вызываемые из браузера.NET methods invoked from the browser

Не следует доверять вызовам от JavaScript к методам .NET.Don't trust calls from JavaScript to .NET methods. Когда метод .NET предоставляется JavaScript, рассмотрите способ вызова метода .NET:When a .NET method is exposed to JavaScript, consider how the .NET method is invoked:

  • Рассматривайте любой метод .NET, предоставляемый JavaScript, так же, как общедоступная конечная точка приложения.Treat any .NET method exposed to JavaScript as you would a public endpoint to the app.
    • Проверьте входные данные.Validate input.
      • Убедитесь, что значения находятся в пределах ожидаемых диапазонов.Ensure that values are within expected ranges.
      • Убедитесь, что у пользователя есть разрешение на выполнение запрошенного действия.Ensure that the user has permission to perform the action requested.
    • Не выделяйте чрезмерное количество ресурсов в рамках вызова метода .NET.Don't allocate an excessive quantity of resources as part of the .NET method invocation. Например, выполните проверки и ограничения на использование ЦП и памяти.For example, perform checks and place limits on CPU and memory use.
    • Примите во внимание, что статический метод и методы экземпляра могут предоставляться клиентам JavaScript.Take into account that static and instance methods can be exposed to JavaScript clients. Избегайте совместного использования состояний в сеансах, если только не вызывается конструктор для предоставления общего состояния с соответствующими ограничениями.Avoid sharing state across sessions unless the design calls for sharing state with appropriate constraints.
      • Для методов экземпляров, предоставляемых через объекты DotNetReference, которые изначально были созданы с помощью внедрения зависимостей (DI), объекты должны быть зарегистрированы как объекты с областью действия.For instance methods exposed through DotNetReference objects that are originally created through dependency injection (DI), the objects should be registered as scoped objects. Это относится к любой службе DI, используемой приложением Blazor Server.This applies to any DI service that the Blazor Server app uses.
      • Для статических методов Избегайте установки состояния, которое не может быть ограничено клиентом, если только приложение явно не предоставляет состояние по-проектированию для всех пользователей на экземпляре сервера.For static methods, avoid establishing state that can't be scoped to the client unless the app is explicitly sharing state by-design across all users on a server instance.
    • Старайтесь не передавать пользовательские данные в параметрах вызовов JavaScript.Avoid passing user-supplied data in parameters to JavaScript calls. Если передача данных в параметрах является абсолютно обязательной, убедитесь, что код JavaScript обрабатывает передачу данных без введения уязвимостей межсайтовых сценариев (XSS) .If passing data in parameters is absolutely required, ensure that the JavaScript code handles passing the data without introducing Cross-site scripting (XSS) vulnerabilities. Например, не записывайте данные, предоставленные пользователем, в модель DOM (DOM), установив свойство innerHTML элемента.For example, don't write user-supplied data to the Document Object Model (DOM) by setting the innerHTML property of an element. Рассмотрите возможность использования политики безопасности содержимого (CSP) для отключения eval и других ненадежных примитивов JavaScript.Consider using Content Security Policy (CSP) to disable eval and other unsafe JavaScript primitives.
  • Избегайте реализации пользовательского диспетчеризации вызовов .NET поверх реализации диспетчеризации платформы.Avoid implementing custom dispatching of .NET invocations on top of the framework's dispatching implementation. Предоставление доступа к методам .NET для браузера является расширенным сценарием, не рекомендуемым для общих Blazor разработки.Exposing .NET methods to the browser is an advanced scenario, not recommended for general Blazor development.

событияEvents

События предоставляют точку входа для серверного приложения Blazor.Events provide an entry point to a Blazor Server app. Те же правила защиты конечных точек в веб-приложениях применяются к обработке событий в приложениях Blazor Server.The same rules for safeguarding endpoints in web apps apply to event handling in Blazor Server apps. Вредоносный клиент может отправить в качестве полезных данных для события любые данные, которые он хочет отправить.A malicious client can send any data it wishes to send as the payload for an event.

Например:For example:

  • Событие изменения для <select> может отправить значение, не находящиеся в параметрах, представленных приложением для клиента.A change event for a <select> could send a value that isn't within the options that the app presented to the client.
  • <input> может отправить на сервер текстовые данные, минуя проверку на стороне клиента.An <input> could send any text data to the server, bypassing client-side validation.

Приложение должно проверить данные для любого события, обрабатываемого приложением.The app must validate the data for any event that the app handles. Компоненты форм Blazor Framework выполняют основные проверки.The Blazor framework forms components perform basic validations. Если приложение использует пользовательские компоненты форм, для проверки правильности данных событий необходимо написать пользовательский код.If the app uses custom forms components, custom code must be written to validate event data as appropriate.

события сервера Blazor являются асинхронными, поэтому несколько событий можно отправить на сервер, прежде чем приложение сможет реагировать на них, создавая новый рендеринг.Blazor Server events are asynchronous, so multiple events can be dispatched to the server before the app has time to react by producing a new render. Это позволяет учитывать некоторые аспекты безопасности.This has some security implications to consider. Ограничение клиентских действий в приложении должно выполняться внутри обработчиков событий и не зависеть от текущего состояния представления, готового к просмотру.Limiting client actions in the app must be performed inside event handlers and not depend on the current rendered view state.

Рассмотрим компонент счетчика, который должен позволить пользователю увеличить счетчик до трех раз.Consider a counter component that should allow a user to increment a counter a maximum of three times. Кнопка для увеличения счетчика зависит от значения count:The button to increment the counter is conditionally based on the value of count:

<p>Count: @count<p>

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

@code 
{
    private int count = 0;

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

Клиент может отправить одно или несколько событий приращения, прежде чем платформа создаст новый рендеринг этого компонента.A client can dispatch one or more increment events before the framework produces a new render of this component. В результате count может увеличиваться более трех раз пользователем, поскольку кнопка не удаляется в пользовательском интерфейсе достаточно быстро.The result is that the count can be incremented over three times by the user because the button isn't removed by the UI quickly enough. Правильный способ достижения предельного значения в три count показан в следующем примере:The correct way to achieve the limit of three count increments is shown in the following example:

<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) { ... } внутри обработчика решение об увеличении count зависит от текущего состояния приложения.By adding the if (count < 3) { ... } check inside the handler, the decision to increment count is based on the current app state. Решение не зависит от состояния пользовательского интерфейса, которое было в предыдущем примере, что может быть временно устаревшим.The decision isn't based on the state of the UI as it was in the previous example, which might be temporarily stale.

Защита от нескольких отправокGuard against multiple dispatches

Если обратный вызов события вызывает длительную операцию, например получение данных из внешней службы или базы данных, рекомендуется использовать условие.If an event callback invokes a long running operation, such as fetching data from an external service or database, consider using a guard. Это условие может препятствовать постановке пользователем в очередь нескольких операций во время выполнения операции с визуальным отзывом.The guard can prevent the user from queueing up multiple operations while the operation is in progress with visual feedback. Следующий код компонента задает isLoading для true, пока GetForecastAsync получает данные с сервера.The following component code sets isLoading to true while GetForecastAsync obtains data from the server. Хотя isLoading true, кнопка отключена в пользовательском интерфейсе:While isLoading is true, the button is disabled in the UI:

@page "/fetchdata"
@using BlazorServerSample.Data
@inject WeatherForecastService ForecastService

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

@code {
    private bool isLoading;
    private WeatherForecast[] forecasts;

    private async Task UpdateForecasts()
    {
        if (!isLoading)
        {
            isLoading = true;
            forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
            isLoading = false;
        }
    }
}

Отмена в начале и избежание использования-After-DisposeCancel early and avoid use-after-dispose

В дополнение к использованию защиты, как описано в разделе Защита от нескольких исправлений , рассмотрите возможность использования CancellationToken для отмены длительных операций при удалении компонента.In addition to using a guard as described in the Guard against multiple dispatches section, consider using a CancellationToken to cancel long-running operations when the component is disposed. Этот подход обладает дополнительными преимуществами для предотвращения использования после удаления в компонентах:This approach has the added benefit of avoiding use-after-dispose in components:

@implements IDisposable

...

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

    private async Task UpdateForecasts()
    {
        ...

        forecasts = await ForecastService.GetForecastAsync(DateTime.Now, 
            TokenSource.Token);

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

        ...
    }

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

Избегайте событий, создающих большие объемы данныхAvoid events that produce large amounts of data

Некоторые события модели DOM, такие как oninput или onscroll, могут создавать большой объем данных.Some DOM events, such as oninput or onscroll, can produce a large amount of data. Избегайте использования этих событий в приложениях Blazor Server.Avoid using these events in Blazor server apps.

Дополнительные рекомендации по безопасностиAdditional security guidance

Рекомендации по защите ASP.NET Core приложений применяются к приложениям Blazor Server и рассматриваются в следующих разделах:The guidance for securing ASP.NET Core apps apply to Blazor Server apps and are covered in the following sections:

Ведение журнала и конфиденциальные данныеLogging and sensitive data

Взаимодействие взаимодействия между клиентом и сервером осуществляется в журналы сервера с помощью ILogger экземпляров.JS interop interactions between the client and server are recorded in the server's logs with ILogger instances. Blazor позволяет избежать записи конфиденциальных данных, таких как фактические события или входные данные взаимодействия JS и выходов. avoids logging sensitive information, such as actual events or JS interop inputs and outputs.

При возникновении ошибки на сервере платформа уведомляет клиента и слезами сеанс.When an error occurs on the server, the framework notifies the client and tears down the session. По умолчанию клиент получает общее сообщение об ошибке, которое можно увидеть в средствах разработчика браузера.By default, the client receives a generic error message that can be seen in the browser's developer tools.

Ошибка на стороне клиента не включает стек вызовов и не предоставляет сведений о причине ошибки, но журналы сервера содержат такие сведения.The client-side error doesn't include the callstack and doesn't provide detail on the cause of the error, but server logs do contain such information. В целях разработки конфиденциальные сведения об ошибках можно сделать доступными для клиента, включив подробные ошибки.For development purposes, sensitive error information can be made available to the client by enabling detailed errors.

Включить подробные сведения об ошибках с помощью:Enable detailed errors with:

  • CircuitOptions.DetailedErrors.CircuitOptions.DetailedErrors.
  • Раздел конфигурации (тип DetailedErrors).DetailedErrors configuration key. Например, задайте для переменной среды ASPNETCORE_DETAILEDERRORS значение true.For example, set the ASPNETCORE_DETAILEDERRORS environment variable to a value of true.

Предупреждение

Предоставление сведений об ошибках клиентам в Интернете является угрозой безопасности, которую всегда следует избегать.Exposing error information to clients on the Internet is a security risk that should always be avoided.

Защита информации при передаче с помощью HTTPSProtect information in transit with HTTPS

Сервер Blazor использует SignalR для обмена данными между клиентом и сервером.Blazor Server uses SignalR for communication between the client and the server. Blazor Server обычно использует транспорт, который SignalR согласовывать, обычно это WebSocket. Server normally uses the transport that SignalR negotiates, which is typically WebSockets.

Blazor Server не гарантирует целостность и конфиденциальность данных, передаваемых между сервером и клиентом. Server doesn't ensure the integrity and confidentiality of the data sent between the server and the client. Всегда используйте HTTPS.Always use HTTPS.

Межсайтовые сценарии (XSS)Cross-site scripting (XSS)

Межсайтовые сценарии (XSS) позволяют неавторизованной стороне выполнять произвольную логику в контексте браузера.Cross-site scripting (XSS) allows an unauthorized party to execute arbitrary logic in the context of the browser. Скомпрометированное приложение потенциально может выполнять произвольный код на клиенте.A compromised app could potentially run arbitrary code on the client. Уязвимость может быть использована для выполнения ряда вредоносных действий на сервере.The vulnerability could be used to potentially perform a number of malicious actions against the server:

  • Отправка фиктивных или недопустимых событий на сервер.Dispatch fake/invalid events to the server.
  • Отработка отказа/недопустимые завершения подготовки к просмотру.Dispatch fail/invalid render completions.
  • Избегайте диспетчеризации завершений рендеринга.Avoid dispatching render completions.
  • Отправка вызовов взаимодействия из JavaScript в .NET.Dispatch interop calls from JavaScript to .NET.
  • Измените ответ вызовов взаимодействия с .NET на JavaScript.Modify the response of interop calls from .NET to JavaScript.
  • Избегайте отправки результатов взаимодействия .NET с JS.Avoid dispatching .NET to JS interop results.

Платформа Blazor Server предпринимает меры для защиты от некоторых из предыдущих угроз.The Blazor Server framework takes steps to protect against some of the preceding threats:

  • Прекращает создание новых обновлений пользовательского интерфейса, если клиент не будет подтверждать пакеты отрисовки.Stops producing new UI updates if the client isn't acknowledging render batches. Настроен с CircuitOptions.MaxBufferedUnacknowledgedRenderBatches.Configured with CircuitOptions.MaxBufferedUnacknowledgedRenderBatches.
  • Истечение времени ожидания вызова .NET to JavaScript через одну минуту без получения ответа от клиента.Times out any .NET to JavaScript call after one minute without receiving a response from the client. Настроен с CircuitOptions.JSInteropDefaultCallTimeout.Configured with CircuitOptions.JSInteropDefaultCallTimeout.
  • Выполняет базовую проверку всех входных данных, поступающих из браузера во время взаимодействия с JS:Performs basic validation on all input coming from the browser during JS interop:
    • Ссылки на .NET являются допустимыми и типа, ожидаемого методом .NET..NET references are valid and of the type expected by the .NET method.
    • Данные не имеют неправильный формат.The data isn't malformed.
    • В полезных данных содержится правильное число аргументов для метода.The correct number of arguments for the method are present in the payload.
    • Аргументы или результат можно правильно десериализовать перед вызовом метода.The arguments or result can be deserialized correctly before invoking the method.
  • Выполняет базовую проверку всех входных данных, поступающих от браузера, от отправленных событий:Performs basic validation in all input coming from the browser from dispatched events:
    • Событие имеет допустимый тип.The event has a valid type.
    • Данные для события могут быть десериализованы.The data for the event can be deserialized.
    • С событием связан обработчик событий.There's an event handler associated with the event.

В дополнение к средствам защиты, реализуемым платформой, приложение должно быть закодировано разработчиком для защиты от угроз и выполнения соответствующих действий:In addition to the safeguards that the framework implements, the app must be coded by the developer to safeguard against threats and take appropriate actions:

  • Всегда проверяйте данные при обработке событий.Always validate data when handling events.
  • Предпринимать необходимые действия при получении недопустимых данных:Take appropriate action upon receiving invalid data:
    • Пропускать данные и возвращать.Ignore the data and return. Это позволяет приложению продолжить обработку запросов.This allows the app to continue processing requests.
    • Если приложение определяет, что входные данные столкновении и не могут быть получены законным клиентом, вызовите исключение.If the app determines that the input is illegitimate and couldn't be produced by legitimate client, throw an exception. Создание исключения слезами канал вниз и завершает сеанс.Throwing an exception tears down the circuit and ends the session.
  • Не следует доверять сообщению об ошибке, предоставленному в журналах завершения обработки пакетов, включенных в журналы.Don't trust the error message provided by render batch completions included in the logs. Эта ошибка предоставляется клиентом и не может быть доверенной, так как клиент может быть скомпрометирован.The error is provided by the client and can't generally be trusted, as the client might be compromised.
  • Не следует доверять входным вызовам взаимодействия на JS в любом направлении между методами JavaScript и .NET.Don't trust the input on JS interop calls in either direction between JavaScript and .NET methods.
  • Приложение отвечает за проверку допустимости содержимого аргументов и результатов, даже если аргументы или результаты правильно десериализованы.The app is responsible for validating that the content of arguments and results are valid, even if the arguments or results are correctly deserialized.

Чтобы уязвимость XSS существовала, приложение должно включить пользовательский ввод на странице, подготовленной для просмотра.For a XSS vulnerability to exist, the app must incorporate user input in the rendered page. Blazor серверных компонентов выполняет шаг времени компиляции, при котором разметка в файле Razor преобразуется в процедурную C# логику. Server components execute a compile-time step where the markup in a .razor file is transformed into procedural C# logic. Во время выполнения C# логика создает дерево отрисовки , описывающее элементы, текст и дочерние компоненты.At runtime, the C# logic builds a render tree describing the elements, text, and child components. Это применяется к DOM браузера через последовательность инструкций JavaScript (или сериализуется в HTML в случае предварительной визуализации):This is applied to the browser's DOM via a sequence of JavaScript instructions (or is serialized to HTML in the case of prerendering):

  • Пользовательский ввод, отображаемый с помощью обычных синтаксис Razor (например, @someStringValue), не предоставляет уязвимость XSS, так как синтаксис Razor добавляется в DOM с помощью команд, которые могут записывать только текст.User input rendered via normal Razor syntax (for example, @someStringValue) doesn't expose a XSS vulnerability because the Razor syntax is added to the DOM via commands that can only write text. Даже если значение включает HTML-разметку, значение отображается как статический текст.Even if the value includes HTML markup, the value is displayed as static text. При предварительной отрисовке выходные данные кодируются в формате HTML, что также отображает содержимое в виде статического текста.When prerendering, the output is HTML-encoded, which also displays the content as static text.
  • Теги скриптов не допускаются и не должны включаться в дерево визуализации компонента приложения.Script tags aren't allowed and shouldn't be included in the app's component render tree. Если тег скрипта включен в разметку компонента, создается ошибка времени компиляции.If a script tag is included in a component's markup, a compile-time error is generated.
  • Авторы компонентов могут создавать компоненты C# без использования Razor.Component authors can author components in C# without using Razor. Автор компонента несет ответственность за использование правильных API-интерфейсов при выдаче выходных данных.The component author is responsible for using the correct APIs when emitting output. Например, используйте builder.AddContent(0, someUserSuppliedString), а не builder.AddMarkupContent(0, someUserSuppliedString), так как в последнем случае может быть создана уязвимость XSS.For example, use builder.AddContent(0, someUserSuppliedString) and not builder.AddMarkupContent(0, someUserSuppliedString), as the latter could create a XSS vulnerability.

В рамках защиты от атак XSS рассмотрите возможность реализации предотвращения взлома XSS, например политики безопасности содержимого (CSP).As part of protecting against XSS attacks, consider implementing XSS mitigations, such as Content Security Policy (CSP).

Для получения дополнительной информации см. Предотвращения межсайтовых сценариев (XSS) в ASP.NET Core.For more information, see Предотвращения межсайтовых сценариев (XSS) в ASP.NET Core.

Защита от разных источниковCross-origin protection

Атаки между источниками предполагают, что клиент из другого источника выполняет действие с сервером.Cross-origin attacks involve a client from a different origin performing an action against the server. Вредоносным действием обычно является запрос GET или форма POST (подделка межсайтовых запросов, CSRF), но также возможен открытие вредоносного WebSocket.The malicious action is typically a GET request or a form POST (Cross-Site Request Forgery, CSRF), but opening a malicious WebSocket is also possible. Серверные приложения Blazor предлагают те же гарантии, что и любое другое SignalRное приложение, использующее предложение протокола концентратора:Blazor Server apps offer the same guarantees that any other SignalR app using the hub protocol offer:

  • доступ к Blazor серверным приложениям можно получить из нескольких источников, если только не будут предприняты дополнительные меры для их предотвращения.Blazor Server apps can be accessed cross-origin unless additional measures are taken to prevent it. Чтобы отключить доступ между источниками, отключите CORS в конечной точке, добавив по промежуточного слоя CORS в конвейер и добавив DisableCorsAttribute в метаданные конечной точки Blazor или ограничив набор разрешенных источников, настроив SignalR для совместного использования ресурсов между источниками.To disable cross-origin access, either disable CORS in the endpoint by adding the CORS middleware to the pipeline and adding the DisableCorsAttribute to the Blazor endpoint metadata or limit the set of allowed origins by configuring SignalR for cross-origin resource sharing.
  • Если CORS включен, для защиты приложения могут потребоваться дополнительные действия в зависимости от конфигурации CORS.If CORS is enabled, extra steps might be required to protect the app depending on the CORS configuration. Если CORS глобально включена, CORS можно отключить для центра Blazor Server, добавив DisableCorsAttribute метаданные в метаданные конечной точки после вызова hub.MapBlazorHub().If CORS is globally enabled, CORS can be disabled for the Blazor Server hub by adding the DisableCorsAttribute metadata to the endpoint metadata after calling hub.MapBlazorHub().

Для получения дополнительной информации см. Предотвращение атак с подделкой межсайтовых запросов (XSRF/CSRF) в ASP.NET Core.For more information, see Предотвращение атак с подделкой межсайтовых запросов (XSRF/CSRF) в ASP.NET Core.

ЩелчокClick-jacking

При выборе розетки можно выполнить визуализацию сайта в качестве <iframe> в пределах сайта с другого источника, чтобы заставить пользователя выполнять действия на веб-узле при атаке.Click-jacking involves rendering a site as an <iframe> inside a site from a different origin in order to trick the user into performing actions on the site under attack.

Чтобы защитить приложение от подготовки к просмотру в <iframe>, используйте политику безопасности содержимого (CSP) и заголовок X-Frame-Options.To protect an app from rendering inside of an <iframe>, use Content Security Policy (CSP) and the X-Frame-Options header. Дополнительные сведения см. в разделе MDN Web документация: X-Frame-Options.For more information, see MDN web docs: X-Frame-Options.

Открыть перенаправленияOpen redirects

При запуске сеанса серверного приложения Blazor сервер выполняет базовую проверку URL-адресов, отправляемых в процессе запуска сеанса.When a Blazor Server app session starts, the server performs basic validation of the URLs sent as part of starting the session. Платформа проверяет, является ли базовый URL-адрес родительским по отношению к текущему URL-адресу, прежде чем устанавливать канал.The framework checks that the base URL is a parent of the current URL before establishing the circuit. Платформа не выполняет никаких дополнительных проверок.No additional checks are performed by the framework.

Когда пользователь выбирает ссылку на клиенте, URL-адрес ссылки отправляется на сервер, который определяет, какое действие следует предпринять.When a user selects a link on the client, the URL for the link is sent to the server, which determines what action to take. Например, приложение может выполнить навигацию на стороне клиента или указать браузеру, чтобы перейти к новому расположению.For example, the app may perform a client-side navigation or indicate to the browser to go to the new location.

Компоненты также могут активировать запросы навигации программно с помощью NavigationManager.Components can also trigger navigation requests programatically through the use of NavigationManager. В таких случаях приложение может выполнить навигацию на стороне клиента или указать браузеру, чтобы перейти к новому расположению.In such scenarios, the app might perform a client-side navigation or indicate to the browser to go to the new location.

Компоненты должны:Components must:

  • Старайтесь не использовать входные данные пользователя как часть аргументов вызова навигации.Avoid using user input as part of the navigation call arguments.
  • Проверьте аргументы, чтобы убедиться, что целевой объект разрешен приложением.Validate arguments to ensure that the target is allowed by the app.

В противном случае злонамеренный пользователь может заставить браузер попасть на управляемый злоумышленником сайт.Otherwise, a malicious user can force the browser to go to an attacker-controlled site. В этом случае злоумышленник применяет приложение к использованию некоторых вводимых пользователем данных в ходе вызова метода NavigationManager.Navigate.In this scenario, the attacker tricks the app into using some user input as part of the invocation of the NavigationManager.Navigate method.

Этот Совет также применяется при подготовке к просмотру ссылок в составе приложения:This advice also applies when rendering links as part of the app:

  • По возможности используйте относительные ссылки.If possible, use relative links.
  • Убедитесь, что ссылки на абсолютные адреса являются допустимыми, прежде чем включать их в страницу.Validate that absolute link destinations are valid before including them in a page.

Для получения дополнительной информации см. Предотвращение атак открытого перенаправления в ASP.NET Core.For more information, see Предотвращение атак открытого перенаправления в ASP.NET Core.

Аутентификация и авторизацияAuthentication and authorization

Рекомендации по проверке подлинности и авторизации см. в разделе Проверка подлинности и авторизация в ASP.NET Core Blazor.For guidance on authentication and authorization, see Проверка подлинности и авторизация в ASP.NET Core Blazor.

Контрольный список по безопасностиSecurity checklist

Следующий список вопросов безопасности не является исчерпывающим:The following list of security considerations isn't comprehensive:

  • Проверка аргументов из событий.Validate arguments from events.
  • Проверка входных данных и результатов вызовов взаимодействия JS.Validate inputs and results from JS interop calls.
  • Старайтесь не использовать (или проверять заранее) пользовательский ввод для вызовов взаимодействия .NET to JS.Avoid using (or validate beforehand) user input for .NET to JS interop calls.
  • Запретить клиенту выделение непривязанного объема памяти.Prevent the client from allocating an unbound amount of memory.
    • Данные в компоненте.Data within the component.
    • DotNetObject ссылки, возвращаемые клиенту.DotNetObject references returned to the client.
  • Защита от нескольких диспетчеризации.Guard against multiple dispatches.
  • Отмена длительных операций при удалении компонента.Cancel long-running operations when the component is disposed.
  • Избегайте событий, создающих большие объемы данных.Avoid events that produce large amounts of data.
  • Избегайте использования вводимых пользователем данных в рамках вызовов NavigationManager.Navigate и проверки вводимых пользователем данных для URL-адресов с набором разрешенных источников, в первую очередь, если это не так.Avoid using user input as part of calls to NavigationManager.Navigate and validate user input for URLs against a set of allowed origins first if unavoidable.
  • Не следует принимать решения об авторизации на основе состояния пользовательского интерфейса, но только из состояния компонента.Don't make authorization decisions based on the state of the UI but only from component state.
  • Рассмотрите возможность использования политики безопасности содержимого (CSP) для защиты от атак XSS.Consider using Content Security Policy (CSP) to protect against XSS attacks.
  • Используйте CSP и X-Frame-параметры для защиты от щелчков.Consider using CSP and X-Frame-Options to protect against click-jacking.
  • Убедитесь, что параметры CORS подходят при включении CORS, или явно отключите CORS для приложений Blazor.Ensure CORS settings are appropriate when enabling CORS or explicitly disable CORS for Blazor apps.
  • Убедитесь, что ограничения на стороне сервера для приложения Blazor обеспечивают приемлемое взаимодействие с пользователем без неприемлемых уровней риска.Test to ensure that the server-side limits for the Blazor app provide an acceptable user experience without unacceptable levels of risk.