dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.37k stars 9.99k forks source link

[Blazor] Docs on Blazor Web security #51577

Closed javiercn closed 11 months ago

javiercn commented 12 months ago
javiercn commented 11 months ago

Security considerations for Blazor Web Applications

Blazor web combines three different models in one for writing interactive web applications. Traditional server side rendering, which is a request/response model based on HTTP. Interactive Server Side rendering, which is a rendering model based on SignalR. And finally, client side rendering, which is a rendering model based on WebAssembly.

All the general security considerations defined for the interactive rendering modes apply to Blazor web applications when there are interactive components on the application rendering in one of the given supported render modes. In the following sections we will center on the security considerations that are specific to non interactive Server Renderer Blazor web applications as well as the specific aspects that apply when different render modes interact with each other.

General considerations of the Server Side rendering model

The Server Side rendering model is based on the traditional request/response model of HTTP. As such, there are common areas of concern with regards to security consideration and specific threats that must be taking into account and mitigated successfully. The framework provides built-in mechanims for some of these threats, but other threats are specific to application code and must be handled by the app. These threats can be categorized as follows:

Input validation and sanitization

All input coming from the client must be considered untrusted unless its information that was generated and protected on the server (like a CSRF token or any other payload protected with authenticated encryption, like an auth cookie or a session identifier).

Input is normally available to the app through a binding process, for example via [SupplyParameterFromQuery] or [SupplyParameterFromForm]. Before processing this input, we need to make sure that it is valid. For example, we need to make sure that there were no binding errors when mapping the form data to a component property or otherwise we might be processing invalid data.

In the same way, if the input is used to perform a redirect, we need to make sure that the input is valid and that it is not pointing to a domain we consider valid, or to a subpath within the app base path. Otherwise, we might be exposing the application to open redirection attacks, where an attacker can craft a link that redirects the user to a malicious site.

Finally, if the input is used to perform a database query, we need to make sure that the input is valid and that it is not exposing the application to SQL injection attacks. Otherwise, an attacker might be able to craft a malicious query that can be used to extract information from the database or to modify the database.

Data that might have come from input also needs to be sanitized before included in a response. For example, the input might contain HTML or JavaScript that can be used to perform cross-site scripting attacks, that can be used to extract information from the user or to perform actions on behalf of the user.

The framework provides the following mechanisms to help with input validation and sanitization:

It is important that all input and permissions are validated server side at the time of performing a given action to ensure that the data is valid and accurate at that time and that the user is allowed to perform the action. This approach is consistent with the guidance offered in interactive Blazor Server rendering.

Session management

Session management is handled by the framework. The framework uses a session cookie to identify the user session. The session cookie is protected using the Data Protection APIs. The session cookie is not accessible to JavaScript code running on the browser and is not guessable nor manipulable.

With regards to other session data that might be for example, stored within services, it is fundamental that the session data is stored within scoped services, as those are unique per a given user session, as opposed to singleton services which are shared across all user sessions in a given process instance. When it comes to SSR, there's no much difference between scoped and transient services in most cases as the lifetime of the service is limited to a single request, but it makes a different in two scenarios:

Error handling and logging

The framework provides built-in logging for the application at the framework level. The framework logs important events like when the antiforgery token for a form fails to validate, when a root component starts to render, when an action is dispatched, etc. The app is responsible for logging any other events that might be important to the app.

The framework provides built-in error handling for the application at the framework level. The framework handles errors that happen during the rendering of a component and either uses the error boundary mechanism to display a friendly error message or lets the error bubble up to the exception handling middleware which is configured to render the error page.

Errors that happen during streaming rendering after the response have started to be sent to the client are displayed in the final response as a generic error message. Details about the cause of the error are only included during development.

Data protection

The framework offers mechanisms for protecting sensitive information for a given user session and ensures that the built-in components use these mechanisms to protect sensitive information is aware of, like the user identity when using cookie authentication. Besides that, the app is responsible for protecting any other app specific information. The most common way of doing this is via the data protection APIs or any other form of encryption. As a general rule, the app is responsible for:

With regards to data protection it is also important to clearly understands what code executes where and what the implications for that are. In the server and interactive server mode, the code is stored on the server and never reaches the client. In web assembly, the application code will always reach the client, which means that any sensitive information that is stored in the application code will be available to anyone with access to the app. No matter whether the app uses offuscation or any other similar technique to "protect" the code, once the code reaches the client, it can be reverse engineered and the information extracted.

Denial of service

The framework at the server level provides limits on aspects like the max size of the request, header size, etc. With regards with application code, our form mapping system defines limits similar to those defined by MVC's model binding system:

This aspect has more to do with the difference in growth between the work the client performs and the work the server performs than with a specific 1->N comparison. For example, it can be that a client might submit a workitem (inserting elements into a list) that takes N units of time to perform, but the server needs N^2 to process (because it might be doing something very naive). It's the difference between N and N^2 that matters.

As such, there's a limit on how much "work" the server must be willing to do, which is specific to the app. This aspect applies to Blazor Server at all, since the resources are on the server, but does not necessarily apply to webassembly in most situations.

The other important aspect is that this is not only reserved to CPU time, but it applies to any resources (memory, network, space on disk, etc).

With regards to webassembly, there's normally not an issue with regards to the amount of work the client performs, since the client is normally limited by the resources available on the client. However, there are some scenarios where the client might be impacted by this, if for example, an app displays data from other users and one user is capable of adding data to the system that forces the clients that display the data to perform an amount of work that is not proportional to the amount of data added by the user.

Recommended check list (non exhaustive)

javiercn commented 11 months ago

@guardrex can you put this in the line to add it to the docs?

javiercn commented 11 months ago

Using the referenced issue to track it.