-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
This originally started with the docs issue #34586 - IMovieService example can lead to authorization problems
Possibly related:
- Unsure how to inject HttpClient for InteractiveAuto render mode (RC2) #51468
- Prerendered hosted Blazor WebAssembly errors not addressed by guidance #46737
The current guidance for working with a Web API with SSR/Pre-rendering enabled is to create a server-side and a client-side service implementation.
I view this guidance as problematic from a security standpoint, as it leads to two different authorization stacks being used for the same essential data/operation, which can e.g. cause unintentional data leakage due to forgetting to update either the razor or the web api with the appropriate security requirements.
Copying from the Docs issue:
- Sample project: 9.0/BlazorWebAppEntra/BlazorWebAppEntra.sln
- When rendering in CSR, authorization is enforced by the
/weather-forecast
api (registered in BlazorWebAppEntra/Program.cs- For SSR/pre-rendering authorization is enforced by BlazorWebAppEntra.Client/Pages/Weather.razor
- BlazorWebAppEntra/Weather/ServerWeatherForecaster.cs does not itself perform any authorization checks
- Thus you now have two different authorization stacks in place for the same fundamental data/action.
- In this particular case the authorization requirements are the same
- However, one can quite easily imagine a scenario where the specs say that the data from
IWeatherForecaster
should be restricted byMyPolicy
, and the dev only adds it to the endpoint registration (or vice versa, only adds it to the razor componet), leading to an authorization hole where depending on whether the page is rendered entirely CSR or SSR/pre-rendered you have different policies applied, leading to unintended information disclosure. This is particularly problematic as it can easily escape immediate user-testing as you would have to ensure that you actually access the page both as pure CSR rendering and as SSR/pre-rendered- This problem only gets worse as an application becomes more complex. In the particular case illustrated by the sample, there is a one-to-one correspondence between data exposed by the
/weather-forecast
endpoint and theWeather.razor
page. Such a one-to-one correlation between an api and a razor component is not going to always exist, leading to even more opportunity for unintended information disclosure when different data has different authorization requirements- A potential solution would be to consolidate authorization logic into the
ServerWeatherForecaster.cs
, but that would appear to negate any declarative usage of the ASP.NET Core authorization stack altogether and could cause other problems (e.g., how would you force[Authorize("mypolicy")]
attributes to be checked if they decorated theServerWeatherForecaster
orIWeatherForecaster
? How would that authorization flow through to http401
or403
responses for unauthorized users calling the web api?)
cc: @guardrex dotnet/AspNetCore.Docs#34586
Describe the solution you'd like
A few broad options come to mind:
-
Provide a mechanism to "inline" HttpClient calls
- With today's framework, I believe you could omit the service abstractions and just call the Web API directly during pre-rendering by configuring an HttpClient in the Server project to pass-through the incoming user identity when calling the web api.
- This should resolve concerns about ambiguity during authorization, since authorization for the service becomes the sole responsibility of the web api
- However, doing so would contradict Service abstractions for web API calls:
This section applies to Blazor Web Apps that maintain a web API in the server project or transform web API calls to an external web API.
...
The server version can typically access the server-side resources directly. Injecting an HttpClient on the server that makes calls back to the server isn't recommended, as the network request is typically unnecessary. - This guidance appears to be primarily performance related, so could a mechanism be introduced to optimize HttpClient calls to the same application during pre-rendering?
-
Provide a means to "unify" the authorization stacks between SSR/Pre-rendering and web api.
- So for example, you could decorate your Service interface with with any of the authorization attributes supported by ASP.NET Core in a single place, and both blazor-pre-rendering and web api would honor them from that single interface
- The goal is to have a single, unified authorization stack that applies no matter how the service is called (whether via web api, or SSR/pre-rendering), that is compatible with the current ASP.NET Core web api authorization stack.
-
Provide a more streamlined mechanism to show e.g. a "loading" template for SSR/pre-rendering that resolves to the normal web api once CSR comes online
- In one sense, this is "less ambitious", since it seeks to only pre-render the general page structure instead of pre-rendering the whole page with all data already retrieved
- This is somewhat possible today, as referenced by Unsure how to inject HttpClient for InteractiveAuto render mode (RC2) #51468 (comment)
if you want to change this you either inject a service to detect prerendering or use the OnAfterRenderAsync hook instead of the OnInitlializedAsync Hook. Or disable prerendering.
protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { Text = await _webScraper.Get(); StateHasChanged(); } }
- However:
- this approach does not make an appearance on the documentation page "Call a web API from ASP.NET Core Blazor", and I'm unsure if it has other downsides (my understanding how how Blazor rendering state works still has a lot of holes)
- If you don't get the condition around calling
StateHasChanged()
correct, you can end up getting an infinite loop of calls to your web api StateHasChanged()
seems perhaps too coarse-grained? Thinking here about a component that calls multiple web apis, and perhaps references other components with their own api calls (Again, lots of holes in my current understanding of Blazor rendering state).
Additional context
No response