Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebSocket compression/CSP and security guidance #31918

Merged
merged 3 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aspnetcore/blazor/blazor-ef-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ In the preceding example:

## Enable sensitive data logging

<xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableSensitiveDataLogging%2A> includes application data in exception messages and framework logging. The logged data can include the values assigned to properties of entity instances and parameter values for commands sent to the database. Logging data with <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableSensitiveDataLogging%2A> is a **security risk**, as it may expose passwords and other personally identifiable information (PII) when it logs SQL statements executed against the database.
<xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableSensitiveDataLogging%2A> includes application data in exception messages and framework logging. The logged data can include the values assigned to properties of entity instances and parameter values for commands sent to the database. Logging data with <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableSensitiveDataLogging%2A> is a **security risk**, as it may expose passwords and other [Personally Identifiable Information (PII)](xref:blazor/security/index#personally-identifiable-information-pii) when it logs SQL statements executed against the database.

We recommend only enabling <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableSensitiveDataLogging%2A> for development and testing:

Expand Down
15 changes: 15 additions & 0 deletions aspnetcore/blazor/components/render-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,21 @@ To address this scenario, inject the service in a new imports file placed in the

## Additional resources

:::moniker range=">= aspnetcore-9.0"

* WebSocket compression
* <xref:blazor/fundamentals/signalr#websocket-compression-for-interactive-server-components>
* <xref:blazor/security/server/interactive-server-side-rendering#interactive-server-components-with-websocket-compression-enabled>
* <xref:blazor/js-interop/ssr>
* [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters#cascading-valuesparameters-and-render-mode-boundaries): Also see the [Root-level cascading parameters](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-parameters) section earlier in the article.
* <xref:blazor/components/class-libraries-with-static-ssr>

:::moniker-end

:::moniker range="< aspnetcore-9.0"

* <xref:blazor/js-interop/ssr>
* [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters#cascading-valuesparameters-and-render-mode-boundaries): Also see the [Root-level cascading parameters](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-parameters) section earlier in the article.
* <xref:blazor/components/class-libraries-with-static-ssr>

:::moniker-end
52 changes: 52 additions & 0 deletions aspnetcore/blazor/fundamentals/signalr.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,58 @@ This article explains how to configure and manage SignalR connections in Blazor

For general guidance on ASP.NET Core SignalR configuration, see the topics in the <xref:signalr/introduction> area of the documentation, especially <xref:signalr/configuration#configure-server-options>.

:::moniker range=">= aspnetcore-9.0"

## Websocket compression for Interactive Server components

<!-- UPDATE 9.0 Add API doc cross-links -->

By default, Interactive Server components:

* Enable compression for [WebSocket connections](xref:fundamentals/websockets). `ConfigureWebsocketOptions` controls WebSocket compression.

* Adopt a `frame-ancestors` [Content Security Policy (CSP)](https://developer.mozilla.org/docs/Web/HTTP/CSP) directive set to `'self'`, which only permits embedding the app in an `<iframe>` of the origin from which the app is served when compression is enabled or when a configuration for the WebSocket context is provided. `ContentSecurityFrameAncestorPolicy` controls the `frame-ancestors` CSP.

The `frame-ancestors` CSP can be removed manually by setting the value of `ConfigureWebSocketOptions` to `null`, as you may want to [configure the CSP in a centralized way](xref:blazor/security/content-security-policy). When the `frame-ancestors` CSP is managed in a centralized fashion, care must be taken to apply a policy whenever the first document is rendered. We don't recommend removing the policy completely, as it might make the app vulnerable to attack.

Usage examples:

Disable compression by setting `ConfigureWebSocketOptions` to `null`, which reduces the [vulnerability of the app to attack](xref:blazor/security/server/interactive-server-side-rendering#interactive-server-components-with-websocket-compression-enabled) but may result in reduced performance:

```csharp
builder.MapRazorComponents<App>()
.AddServerRenderMode(o => o.ConfigureWebSocketOptions = null)
```

When compression is enabled, configure a stricter `frame-ancestors` CSP with a value of `'none'` (single quotes required), which allows WebSocket compression but prevents browsers from embedding the app into any `<iframe>`:

```csharp
builder.MapRazorComponents<App>()
.AddServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
```

When compression is enabled, remove the `frame-ancestors` CSP by setting `ContentSecurityFrameAncestorsPolicy` to `null`. This scenario is only recommended for apps that [set the CSP in a centralized way](xref:blazor/security/content-security-policy):

```csharp
builder.MapRazorComponents<App>()
.AddServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = null)
```

> [!IMPORTANT]
> Browsers apply CSP directives from multiple CSP headers using the strictest policy directive value. Therefore, a developer can't add a weaker `frame-ancestors` policy than `'self'` on purpose or by mistake.
>
> Single quotes are required on the string value passed to `ContentSecurityFrameAncestorsPolicy`:
>
> <span aria-hidden="true">❌</span><span class="visually-hidden">Unsupported values:</span> `none`, `self`
>
> <span aria-hidden="true">✔️</span><span class="visually-hidden">Supported values:</span> `'none'`, `'self'`
>
> Additional options include specifying one or more host sources and scheme sources.

For security implications, see <xref:blazor/security/server/interactive-server-side-rendering#interactive-server-components-with-websocket-compression-enabled>. For more information on the `frame-ancestors` directive, see [CSP: `frame-ancestors` (MDN documentation)](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors).

:::moniker-end

:::moniker range=">= aspnetcore-6.0"

## Disable response compression for Hot Reload
Expand Down
19 changes: 19 additions & 0 deletions aspnetcore/blazor/security/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,25 @@ builder.Services.AddCascadingAuthenticationState();

The <xref:Microsoft.AspNetCore.Components.Authorization.CascadingAuthenticationState> component (.NET 7 or earlier) or services provided by <xref:Microsoft.Extensions.DependencyInjection.CascadingAuthenticationStateServiceCollectionExtensions.AddCascadingAuthenticationState%2A> (.NET 8 or later) supplies the `Task<`<xref:Microsoft.AspNetCore.Components.Authorization.AuthenticationState>`>` cascading parameter, which in turn it receives from the underlying <xref:Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider> dependency injection service.

## Personally Identifiable Information (PII)

Microsoft uses the [GDPR definition for 'personal data' (GDPR 4.1)](https://gdpr-text.com/read/article-4/) when documentation discusses Personally Identifiable Information (PII).

PII refers any information relating to an identified or identifiable natural person. An identifiable natural person is one who can be identified, directly or indirectly, with any of the following:

* Name
* Identification number
* Location coordinates
* Online identifier
* Other specific factors
* Physical
* Physiological
* Genetic
* Mental (psychological)
* Economic
* Cultural
* Social identity

## Additional resources

:::moniker range=">= aspnetcore-6.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,37 @@ In constrained environments, such as inside corporate networks or intranets, som
* Doesn't apply in the constrained environment.
* Isn't worth the cost to implement because the security risk is low in a constrained environment.

:::moniker range=">= aspnetcore-9.0"

## Interactive Server Components with WebSocket compression enabled

Compression can expose the app to side-channel attacks against the TLS encryption of the connection, such as [CRIME](https://wikipedia.org/wiki/CRIME_(security_exploit)) and [BREACH](https://wikipedia.org/wiki/BREACH_(security_exploit)) attacks. These types of attacks require that the attacker:

* Force a browser to issue requests with a payload the attacker controls to a vulnerable site via cross-site form posting or by embedding the site inside an iframe of another site.
* Observe the length of the compressed and encrypted response over the network.

For the app to be vulnerable, it must reflect the payload from the attacker in the response, for example, by writing out the path or the query string into the response. Using the length of the response, the attacker can "guess" any information on the response, bypassing the encryption of the connection.

Generally speaking, Blazor apps can enable compression over the WebSocket connection with appropriate security measures:

* The app can be vulnerable when it takes content from the request (for example, the path or query string) that can be influenced by an attacker and reproduces it into the HTML of the page or otherwise makes it part of the response.

* Blazor applies the following security measures automatically:

* When compression is configured, Blazor automatically blocks embedding the app into an iframe, which blocks the initial (uncompressed) response from the server from rendering and precludes the WebSocket connection from ever starting.

* The restriction on embedding the app into an iframe can be relaxed. However, relaxing the restriction exposes the app to attack if the embedding document becomes compromised via a cross-site scripting vulnerability, as that gives the attacker a way to execute the attack.

* Normally for this type of attack to take place, the app must repeatedly reproduce the content in the responses so that the attacker can guess the response. Given how Blazor renders (it renders once and then produces diffs of the content only for the elements that changed) this is hard for an attacker to accomplish. However, it isn't impossible for an attacker, so care must be taken to avoid rendering sensitive information alongside external information that can be manipulated by an attacker. Some examples of this are:

* Render [Personally Identifiable Information (PII)](xref:blazor/security/index#personally-identifiable-information-pii) on the page at the same time as rendering database data that was added by another user.

* Rendering PII information on to the page at the same time as data coming from another user via JS interop or a local singleton service on the server.

In general, we recommend that you avoid rendering components that contain sensitive information alongside components that can render data from untrusted sources as part of the same render batch.

:::moniker-end

## Shared state

[!INCLUDE[](~/blazor/security/includes/shared-state.md)]
Expand Down
Loading