Skip to content

Commit

Permalink
Blazor ROPC (#33749)
Browse files Browse the repository at this point in the history
  • Loading branch information
guardrex authored Oct 8, 2024
1 parent 227c640 commit 2dbbc89
Show file tree
Hide file tree
Showing 12 changed files with 54 additions and 50 deletions.
2 changes: 2 additions & 0 deletions aspnetcore/blazor/blazor-ef-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ The fastest way to create a new <xref:Microsoft.EntityFrameworkCore.DbContext> i
* Using [`DbContextOptions`](/ef/core/miscellaneous/configuring-dbcontext#configuring-dbcontextoptions) to configure the context.
* Using a connection string per <xref:Microsoft.EntityFrameworkCore.DbContext>, such as when you use [ASP.NET Core's Identity model](xref:security/authentication/customize_identity_model). For more information, see [Multi-tenancy (EF Core documentation)](/ef/core/miscellaneous/multitenancy).

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

The recommended approach to create a new <xref:Microsoft.EntityFrameworkCore.DbContext> with dependencies is to use a factory. EF Core 5.0 or later provides a built-in factory for creating new contexts.

:::moniker range="< aspnetcore-5.0"
Expand Down
2 changes: 2 additions & 0 deletions aspnetcore/blazor/components/data-binding.md
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,8 @@ In a more sophisticated and real-world example, the following `PasswordEntry` co
* Exposes changes of a `Password` property to a parent component with an [`EventCallback`](xref:blazor/components/event-handling#eventcallback) that passes in the current value of the child's `password` field as its argument.
* Uses the `onclick` event to trigger the `ToggleShowPassword` method. For more information, see <xref:blazor/components/event-handling>.

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

`PasswordEntry.razor`:

:::moniker range=">= aspnetcore-8.0"
Expand Down
54 changes: 8 additions & 46 deletions aspnetcore/blazor/security/blazor-web-app-with-oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,31 +111,12 @@ The following <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConn

* <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.ClientSecret%2A>: The OIDC client secret.

**The following example is only for testing and demonstration purposes. Don't store the client secret in the app's assembly or check the secret into source control.** Store the client secret in [User Secrets](xref:security/app-secrets), [Azure Key Vault](xref:security/key-vault-configuration), or an [environment variable](xref:fundamentals/configuration/index#non-prefixed-environment-variables).

Authentication scheme configuration is automatically read from `builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"]`, where the `{SCHEME NAME}` placeholder is the scheme, which is `MicrosoftOidc`. Because configuration is preconfigured, a client secret can automatically be read via the `Authentication:Schemes:MicrosoftOidc:ClientSecret` configuration key. On the server using environment variables, name the environment variable `Authentication__Schemes__MicrosoftOidc__ClientSecret`:
Don't store the client secret in the app's assembly or check the secret into source control. For more information, see [Securely maintain sensitive data and credentials](xref:blazor/security/index#securely-maintain-sensitive-data-and-credentials).

```dotnetcli
set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
```
**For local development and testing**, use one of the following approaches:

**For demonstration and testing only**, the <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.ClientSecret%2A> can be set directly. Don't set the value directly for deployed production apps. For slightly improved security, [conditionally compile](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) the line with the `DEBUG` symbol:

```csharp
#if DEBUG
oidcOptions.ClientSecret = "{CLIENT SECRET}";
#endif
```

Example:

Client secret (`{CLIENT SECRET}`): `463471c8c4...f90d674bc9` (shortened for display)

```csharp
#if DEBUG
oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
#endif
```
* Use the [Secret Manager tool](xref:security/app-secrets) to secure the secret locally.
* Authentication scheme configuration is automatically read from `builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"]`, where the `{SCHEME NAME}` placeholder is the scheme, which is `MicrosoftOidc`. The client secret can automatically be read during local development via the `Authentication:Schemes:MicrosoftOidc:ClientSecret` configuration key from an `appsettings.Development.json` file.

* <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.ResponseType%2A>: Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode.

Expand Down Expand Up @@ -379,31 +360,12 @@ The following <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConn

* <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.ClientSecret%2A>: The OIDC client secret.

**The following example is only for testing and demonstration purposes. Don't store the client secret in the app's assembly or check the secret into source control.** Store the client secret in [User Secrets](xref:security/app-secrets), [Azure Key Vault](xref:security/key-vault-configuration), or an [environment variable](xref:fundamentals/configuration/index#non-prefixed-environment-variables).

Authentication scheme configuration is automatically read from `builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"]`, where the `{SCHEME NAME}` placeholder is the scheme, which is `MicrosoftOidc`. Because configuration is preconfigured, a client secret can automatically be read via the `Authentication:Schemes:MicrosoftOidc:ClientSecret` configuration key. On the server using environment variables, name the environment variable `Authentication__Schemes__MicrosoftOidc__ClientSecret`:
Don't store the client secret in the app's assembly or check the secret into source control. For more information, see [Securely maintain sensitive data and credentials](xref:blazor/security/index#securely-maintain-sensitive-data-and-credentials).

```dotnetcli
set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
```
**For local development and testing**, use one of the following approaches:

**For demonstration and testing only**, the <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.ClientSecret%2A> can be set directly. Don't set the value directly for deployed production apps. For slightly improved security, [conditionally compile](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) the line with the `DEBUG` symbol:

```csharp
#if DEBUG
oidcOptions.ClientSecret = "{CLIENT SECRET}";
#endif
```

Example:

Client secret (`{CLIENT SECRET}`): `463471c8c4...f90d674bc9` (shortened for display)

```csharp
#if DEBUG
oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
#endif
```
* Use the [Secret Manager tool](xref:security/app-secrets) to secure the secret locally.
* Authentication scheme configuration is automatically read from `builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"]`, where the `{SCHEME NAME}` placeholder is the scheme, which is `MicrosoftOidc`. The client secret can automatically be read during local development via the `Authentication:Schemes:MicrosoftOidc:ClientSecret` configuration key from an `appsettings.Development.json` file.

* <xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.ResponseType%2A>: Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
> [!WARNING]
> Don't store app secrets, connection strings, credentials, passwords, personal identification numbers (PINs), private C#/.NET code, or private keys/tokens in client-side code, which is ***always insecure***. In test/staging and production environments, server-side Blazor code and web APIs should use secure authentication flows that avoid maintaining credentials within project code or configuration files. Outside of local development testing, we recommend avoiding the use of environment variables to store sensitive data, as environment variables aren't the most secure approach. For local development testing, the [Secret Manager tool](xref:security/app-secrets) is recommended for securing sensitive data. For more information, see [Securely maintain sensitive data and credentials](xref:blazor/security/index#securely-maintain-sensitive-data-and-credentials).
11 changes: 11 additions & 0 deletions aspnetcore/blazor/security/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ ASP.NET Core abstractions, such as <xref:Microsoft.AspNetCore.Identity.SignInMan
> [!NOTE]
> The code examples in this article adopt [nullable reference types (NRTs) and .NET compiler null-state static analysis](xref:migration/50-to-60#nullable-reference-types-nrts-and-net-compiler-null-state-static-analysis), which are supported in ASP.NET Core in .NET 6 or later. When targeting ASP.NET Core 5.0 or earlier, remove the null type designation (`?`) from examples in this article.
## Securely maintain sensitive data and credentials

Don't store app secrets, connection strings, credentials, passwords, personal identification numbers (PINs), private .NET/C# code, or private keys/tokens in client-side code, which is ***always insecure***. Client-side Blazor code should access secure services and databases through a secure web API that you control.

In test/staging and production environments, server-side Blazor code and web APIs should use secure authentication flows that avoid maintaining credentials within project code or configuration files. Outside of local development testing, we recommend avoiding the use of environment variables to store sensitive data, as environment variables aren't the most secure approach. For local development testing, the [Secret Manager tool](xref:security/app-secrets) is recommended for securing sensitive data. For more information, see the following resources:

* [Secure authentication flows (ASP.NET Core documentation)](xref:security/index#secure-authentication-flows)
* [Managed identities for Microsoft Azure services (this article)](#managed-identities-for-microsoft-azure-services)

For client-side and server-side local development and testing, use the [Secret Manager tool](xref:security/app-secrets) to secure sensitive credentials.

## Managed identities for Microsoft Azure services

For Microsoft Azure services, we recommend using *managed identities*. Managed identities securely authenticate to Azure services without storing credentials in app code. For more information, see the following resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ builder.Services.Configure<AuthMessageSenderOptions>(builder.Configuration);

## Configure a user secret for the provider's security key

Set the key with the [secret-manager tool](xref:security/app-secrets). In the following example, the key name is `EmailAuthKey` and the key is represented by the `{KEY}` placeholder. In a command shell, navigate to the app's root folder and execute the following command with the API key:
Set the key with the [Secret Manager tool](xref:security/app-secrets). In the following example, the key name is `EmailAuthKey`, and the key is represented by the `{KEY}` placeholder. In a command shell, navigate to the app's root folder and execute the following command with the API key:

```dotnetcli
dotnet user-secrets set "EmailAuthKey" "{KEY}"
```

For more information, see <xref:security/app-secrets>.

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

## Implement `IEmailSender`

Implement `IEmailSender` for the provider. The following example is based on Mailchimp's Transactional API using [Mandrill.net](https://www.nuget.org/packages/Mandrill.net). For a different provider, refer to their documentation on how to implement sending a message in the `Execute` method.
Expand Down
9 changes: 9 additions & 0 deletions aspnetcore/blazor/security/server/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ Blazor differs from a traditional server-rendered web apps that make new HTTP re
> [!NOTE]
> The code examples in this article adopt [nullable reference types (NRTs) and .NET compiler null-state static analysis](xref:migration/50-to-60#nullable-reference-types-nrts-and-net-compiler-null-state-static-analysis), which are supported in ASP.NET Core in .NET 6 or later. When targeting ASP.NET Core 5.0 or earlier, remove the null type designation (`?`) from the examples in this article.
## Server-side security of sensitive data and credentials

In test/staging and production environments, server-side Blazor code and web APIs should use secure authentication flows that avoid maintaining credentials within project code or configuration files. Outside of local development testing, we recommend avoiding the use of environment variables to store sensitive data, as environment variables aren't the most secure approach. For local development testing, the [Secret Manager tool](xref:security/app-secrets) is recommended for securing sensitive data. For more information, see the following resources:

* [Secure authentication flows (ASP.NET Core documentation)](xref:security/index#secure-authentication-flows)
* [Managed identities for Microsoft Azure services (Blazor documentation)](xref:blazor/security/index#managed-identities-for-microsoft-azure-services)

For client-side and server-side local development and testing, use the [Secret Manager tool](xref:security/app-secrets) to secure sensitive credentials.

## Project template

Create a new server-side Blazor app by following the guidance in <xref:blazor/tooling>.
Expand Down
6 changes: 4 additions & 2 deletions aspnetcore/blazor/security/webassembly/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ Blazor WebAssembly apps are secured in the same manner as single-page applicatio

The Blazor WebAssembly security documentation primarily focuses on how to accomplish user authentication and authorization tasks. For OAuth 2.0/OIDC general concept coverage, see the resources in the [main overview article's *Additional resources* section](xref:blazor/security/index#additional-resources).

## Client-side/SPA security
## Client-side/SPA security of sensitive data and credentials

A Blazor WebAssembly app's .NET/C# codebase is served to clients, and the app's code can't be protected from inspection and tampering by users. Never place anything of a secret nature into a Blazor WebAssembly app, such as private .NET/C# code, security keys, passwords, or any other type of sensitive information.
A Blazor WebAssembly app's .NET/C# codebase is served to clients, and the app's code can't be protected from inspection and tampering by users. Never place credentials or secrets into a Blazor WebAssembly app, such as app secrets, connection strings, passwords, private .NET/C# code, or other sensitive data.

To protect .NET/C# code and use [ASP.NET Core Data Protection](xref:security/data-protection/introduction) features to secure data, use a server-side ASP.NET Core web API. Have the client-side Blazor WebAssembly app call the server-side web API for secure app features and data processing. For more information, see <xref:blazor/call-web-api?pivots=webassembly> and the articles in this node.

For local development testing, the [Secret Manager tool](xref:security/app-secrets) is recommended for securing sensitive data.

## Authentication library

Blazor WebAssembly supports authenticating and authorizing apps using OIDC via the [`Microsoft.AspNetCore.Components.WebAssembly.Authentication`](https://www.nuget.org/packages/Microsoft.AspNetCore.Components.WebAssembly.Authentication) library using the [Microsoft identity platform](/entra/identity-platform/). The library provides a set of primitives for seamlessly authenticating against ASP.NET Core backends. The library can authenticate against any third-party Identity Provider (IP) that supports OIDC, which are called OpenID Providers (OP).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ For additional Identity scenarios provided by the API, see <xref:security/authen
* Recovery codes
* User info management

## Use secure authentication flows to maintain sensitive data and credentials

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

## Sample apps

In this article, sample apps serve as a reference for standalone Blazor WebAssembly apps that access ASP.NET Core Identity through a backend web API. The demonstration includes two apps:
Expand Down
2 changes: 2 additions & 0 deletions aspnetcore/blazor/tutorials/movie-database-app/part-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ The `Routes` component (`Routes.razor`) sets up routing for the app.

The `appsettings.json` file contains configuration data, such as connection strings.

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

### `Program.cs` file

The `Program.cs` file contains code to create the app and configure the request processing pipeline of the app.
Expand Down
4 changes: 4 additions & 0 deletions aspnetcore/blazor/tutorials/movie-database-app/part-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ The `appsettings.json` file is updated with the connection string used to connec
}
```

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

## Files created and updated by scaffolding

The scaffolding process creates the following component files and movie database context class file:
Expand Down Expand Up @@ -414,6 +416,8 @@ The database context `BlazorWebAppMoviesContext` (`Data/BlazorWebAppMoviesContex

The name of the connection string is passed in to the context by calling a method on a <xref:Microsoft.EntityFrameworkCore.DbContextOptions> object. For local development, the connection string is read from the `appsettings.json` file.

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

## Test the app

Run the app.
Expand Down
4 changes: 3 additions & 1 deletion aspnetcore/blazor/tutorials/movie-database-app/part-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ The following is an example connection string:

> :::no-loc text="Server=(localdb)\\mssqllocaldb;Database=BlazorWebAppMoviesContext-c347f669-bddf-56a3-a32e-7fe010306593;Trusted_Connection=True;MultipleActiveResultSets=true":::
When the app is deployed to a test/staging or production server, an environment variable can be used to set the connection string to a test/staging or production database server.
When the app is deployed to a test/staging or production server, securely store the connection string outside of the project's configuration files.

[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)]

## Database technology

Expand Down

0 comments on commit 2dbbc89

Please sign in to comment.