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

Make blazor.server.js compatible with strict CSS CSP #58629

Closed
1 task done
michaelongithub opened this issue Oct 25, 2024 · 11 comments · Fixed by #60376
Closed
1 task done

Make blazor.server.js compatible with strict CSS CSP #58629

michaelongithub opened this issue Oct 25, 2024 · 11 comments · Fixed by #60376
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Priority:1 Work that is critical for the release, but we could probably ship without
Milestone

Comments

@michaelongithub
Copy link

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.

blazor.server.js creates sometimes inline styles dynamically at runtime. This is a violation of strict Css CSP Policies. Workarounds with JS CreateElement and analogous tricks is unsafe itself, because it defeats the purpose of CSP by creating a bypass mechanism and is vulnerable to being overwritten by XSS attacks.

Describe the solution you'd like

The framework itself should provide a possibility (flag,option,...) to create CSP nonces for by the framework generated inline styles.

Additional context

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Oct 25, 2024
@javiercn
Copy link
Member

@michaelongithub thanks for contacting us.

Rather than doing this, we would likely move the relevant UI into the templates. I suspect the issues you are having are with the reconnect UI. Is that the case?

@javiercn javiercn added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Oct 25, 2024
@michaelongithub
Copy link
Author

Hi javiercn
not sure I understand your remark. It is really blazor.server.js that creates sometimes inline styles dynamically at runtime. This seems to be generally known and if one checks the source of the violation it produces in the browsers devtools, it is visible, that it stems from there. If one has the organizational requirement to have a strict CSS CSP, inline styles are not allowed. So there is a conflict. I have no preference, where one can tell the Blazor Server framework to create nonces for the inline css it creates. But as I understand the nature of the situation, the framework itself must do that.

Alternatively: provide guidance and example on how to mitigate this problem and allow Blazor Server apps to adhere to strict CSS CSP without JS hacks or relaxing the CSP Policy.

@dotnet-policy-service dotnet-policy-service bot added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Oct 25, 2024
@javiercn
Copy link
Member

javiercn commented Oct 25, 2024

@michaelongithub we ship that UI within blazor.server.js, nothing precludes us from ejecting it into the template, where you have full control over it, and doesn't have to inline anything.

I'd rather us update blazor.server.js to be compliant with the strictest csp policy rather than add "patches" to pass nonces, that was the only comment.

@javiercn javiercn removed the Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. label Oct 25, 2024
@javiercn javiercn added this to the .NET 10 Planning milestone Oct 25, 2024
@michaelongithub
Copy link
Author

javiercn:
Thanks again for the swift reaction.
So does that mean that future versions (starting when ?, or hotfix ?) of blazor.server.js wont create inline styles by themself any longer ?

@michaelongithub michaelongithub changed the title Provide an option for Blazor server to create a nonce for the at runtime by the framework dynamically created inline css styles Make blazor.server.js compatible with strict CSS CSP Oct 26, 2024
@danroth27 danroth27 added the Priority:1 Work that is critical for the release, but we could probably ship without label Jan 13, 2025
@javiercn
Copy link
Member

javiercn commented Feb 6, 2025

@oroztocil when you fix #57453 make sure that this is unblocked in that scenario.

For context, the plan is to address this issue by moving the UI into the project template as part of #57453 at that point the solution for existing apps would be to add the same code that will ship in the template into their projects.

We should have an E2E test validating that we can successfully setup a strict CSP policy.

@michaelongithub
Copy link
Author

I had thought this was a general problem, not only for the reconnect ui. is the reconnect ui really the only component where blazor.web.js creates style attributes dynamically. if yes my understanding is that this remains a general problem. if it is just necessary for the blazor framework to create style attributes dynamically to have a reasonably working gui (like the major component providers do it). I have some clients that are very concerned that blazor server does not adhere to strict css csp and such apps have to be run with style-src 'unsafe-inline'

@javiercn
Copy link
Member

had thought this was a general problem, not only for the reconnect ui. is the reconnect ui really the only component where blazor.web.js creates style attributes dynamically.

Blazor doesn't treat style attributes in any special way. If your component sets up those attributes dynamically that's not a problem Blazor can solve. The only location where we ourselves were doing this was within the reconnect UI.

if it is just necessary for the blazor framework to create style attributes dynamically to have a reasonably working gui (like the major component providers do it)

This is definitely not required in Blazor nor any other framework for that matter (Blazor is not specially handling anything here). This is completely an implementation choice for specific component vendors (I don't know which ones do this, but I would be surprised).

The point in the end here is that any other violation it's the responsibility of the app/library authors and not Blazor. We recommend if you have such instances to follow up with the specific vendors/authors as they are the only ones that can help in that regard.

@michaelongithub
Copy link
Author

@javiercn thanks a lot for your prompt clarifications. very helpful. will let the component provider know immediately

@AlexChuev
Copy link

Hi @javiercn,

Let me add a few points from a UI component developer perspective. UI components sometimes require parameters that will ultimately be translated to CSS. A simple example is a Data Grid and its columns:

<DataGrid>
    <DataGridColumn Width="90px" />
    <DataGridColumn Width="120px" />
</DataGrid>

In basic scenarios, you could skip the Width parameter and specify column widths via CSS:

<style>
    .column1 {
        width: 90px;
    }
    .column2 {
        width: 120px;
    }
</style>
<DataGrid>
    <DataGridColumn Class="column1" />
    <DataGridColumn Class="column2" />
</DataGrid>

However, this approach makes the code less readable and will not work in more complex scenarios, where end-users need to change column widths, and this information is saved/restored between sessions.

The problem with the Width parameter (and any other parameters that translate to CSS) is that they create inline styles and thus, violate strict CSP policies:

<table>
    <colgroup>
        <col style="width: 90px;">
        <col style="width: 120px;">
    </colgroup>
    ...
</table>

An alternative would be to create CSS styles on the client via JS Interop. However, JS Interop is only available after the first render, and is not available at all during prerender and in Static render mode. If a Data Grid renders with default column widths, and then adjusts column widths in JS, its users will see columns jump when they first open the page. This will ultimately lead to flaky controls and worse UX overall.

Do you have any tips/guidelines for component developers on how to implement parameters that affect CSS so that they comply with strict CSP policies and apply on the first component render, regardless of the chosen render mode?

@snympi
Copy link

snympi commented Mar 7, 2025

@danroth27 @javiercn given the complexities of CSP compliance and the hoops we have to jump through to change the reconnect UI style for dark mode, text in other languages etc. it seems that ejecting the reconnect template, UI, styles into external components makes sense because it solves many issues.

In the meantime @javiercn mentioned that you can roll your own UI for reconnect and the Blazor docs mention it:
https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-10.0#reflect-the-server-side-connection-state-in-the-ui
This workaround has major other problems because it fails to detect a server restart when the old circuit is not available any more. The auto reload when a new circuit is used works well in the default reconnect, but it has the issues mentioned before.

Dan, you just been mentioned this bug as part of .net 10 release, but does that mean this improvement will only be available towards the end of the year? Given the nature of this is there a way to have this available earlier for production use?

@javiercn
Copy link
Member

Hi @javiercn,

Let me add a few points from a UI component developer perspective. UI components sometimes require parameters that will ultimately be translated to CSS. A simple example is a Data Grid and its columns:

<DataGrid>
    <DataGridColumn Width="90px" />
    <DataGridColumn Width="120px" />
</DataGrid>

In basic scenarios, you could skip the Width parameter and specify column widths via CSS:

<style>
    .column1 {
        width: 90px;
    }
    .column2 {
        width: 120px;
    }
</style>
<DataGrid>
    <DataGridColumn Class="column1" />
    <DataGridColumn Class="column2" />
</DataGrid>

However, this approach makes the code less readable and will not work in more complex scenarios, where end-users need to change column widths, and this information is saved/restored between sessions.

The problem with the Width parameter (and any other parameters that translate to CSS) is that they create inline styles and thus, violate strict CSP policies:

<table>
    <colgroup>
        <col style="width: 90px;">
        <col style="width: 120px;">
    </colgroup>
    ...
</table>

An alternative would be to create CSS styles on the client via JS Interop. However, JS Interop is only available after the first render, and is not available at all during prerender and in Static render mode. If a Data Grid renders with default column widths, and then adjusts column widths in JS, its users will see columns jump when they first open the page. This will ultimately lead to flaky controls and worse UX overall.

Do you have any tips/guidelines for component developers on how to implement parameters that affect CSS so that they comply with strict CSP policies and apply on the first component render, regardless of the chosen render mode?

Unfortunately, this is not a Blazor specific problem, but a general browser limitation. There are two ways to approach this:

  • In the future, you'll be able to use the attr function within your CSS to access the value from the markup and use that directly.

  • Currently you can use a custom CSS property and emit a <style></style> tag with a nonce that sets the custom property for that element with a rule that only targets it individually.

  • Component usage

<MyComponent Color="red" />
  • Component styles
p { color: var(--component-color, blue) }
  • Generated HTML
<div data-props-id="guid">
  <p>My element</p>
</div>
<style nonce="<<crypto-random>>">
[data-props-id="guid"] {
  --component-color: "Red"
}
</style>

Note that this is just a sketch of a possible solution, but in the end, it's not something that the framework should solve, but something that the platform should provide/solve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components Priority:1 Work that is critical for the release, but we could probably ship without
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants