Scott Hanselman

.NET 6 Hot Reload and "Refused to connect to ws: because it violates the Content Security Policy directive" because Web Sockets

November 16, 2021 Comment on this post [7] Posted in DotNetCore
Sponsored By

If you're excited about Hot Reload like me AND you also want an "A" grade from SecurityHeaders.com (really, go try this now) then you will learn very quickly about Content-Security-Policy headers. You need to spend some time reading and you may end up with a somewhat sophisticated list of allowed things, scripts, stylesheets, etc.

In DasBlog Core (the cross platform blog engine that runs this blog) Mark Downie makes these configurable and uses the NWebSpec ASP.NET Middleware library to add the needed headers.

if (SecurityStyleSources != null && SecurityScriptSources != null && DefaultSources != null)
{
app.UseCsp(options => options
.DefaultSources(s => s.Self()
.CustomSources(DefaultSources)
)
.StyleSources(s => s.Self()
.CustomSources(SecurityStyleSources)
.UnsafeInline()
)
.ScriptSources(s => s.Self()
.CustomSources(SecurityScriptSources)
.UnsafeInline()
.UnsafeEval()
)
);
}

Each of those variables comes out of a config file. Yes, it would be more security if they came out of a vault or were even hard coded.

DasBlog is a pretty large and cool app and we noticed immediately upon Mark upgrading it to .NET 6 that we were unable to use Hot Reload (via dotnet watch or from VS 2022). We can complain about it, or we can learn about how it works and why it's not working for us!

Remember: Nothing in your computer is hidden from you.

Starting with a simple "View Source" we can see a JavaScript include at the very bottom that is definitely not mine!

<script src="/_framework/aspnetcore-browser-refresh.js"></script>

Ok, this makes sense as we know not only does HotReload support C# (code behinds) but also Markup via Razor Pages and changing CSS! It would definitely need to communicate "back home" to the runner which is either "dotnet watch" or VS2022.

If I change the ASPNETCORE_ENVIRONMENT to "Production" (either via launch.json, launchsettings, or an environment variable like this, I can see that extra HotReload helper script isn't there:

C:\github\wshotreloadtest>dotnet run --environment="Production"
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7216
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5216

Remember: You never want to use dotnet run in production! It's an SDK building command! You'll want to use dotnet exec your.dll, dotnet your.dll, or best of all, in .NET 6 just call the EXE directly! .\bin\Debug\net6.0\wshotreloadtest.exe in my example. Why? dotnet run will always assume it's in Development (you literally tell it to restore, build, and exec in one run command) if you run it. You'll note that running the actual EXE is always WAY faster as well! Don't ship your .NET SDK to your webserver and don't recompile the whole thing on startup in production!

We can see that that aspnnetcore-browser-refresh.js is the client side of Development-time HotReload. Looking at our browser console we see :

Refused to Connect because it violates a CSP Directive

Refused to connect to 'wss://localhost:62486/' 
because it violates the following Content Security Policy
directive: "default-src 'self'".
Note that 'connect-src' was not explicitly set,
so 'default-src' is used as a fallback.

That's a lot to think about. I started out my ASP.NET Web App's middle ware saying it was OK to talk "back to myself" but nowhere else.

app.UseCsp(options => options.DefaultSources(s => s.Self())); 

Hm, self seems reasonable, why can't the browser connect BACK to the dotnet run'ed Kestrel Web Server? It's all localhost, right? Well, specifically it's http://localhost not ws://localhost, or even wss://localhost (that extra s is for secure) so I need to explicitly allow ws: or wss: or both, but only in Development.

Maybe like this (again, I'm using NWebSpec, but these are just HTTP Headers so you can literally just add them if you want, hardcoded.)

app.UseCsp(options => options.DefaultSources(s => s.Self())
.ConnectSources(s => s.CustomSources("wss://localhost:62895")));

But port numbers change, right? Let's do just wss:, only in Development. Now, if I'm using both CSPs and WebSockets (ws:, wss:) in Production, I'll need to be intentional about this.

What's the moral?

If you start using CSP Headers to tighten things up, be conscious and aware of the headers you need for conveniences like Hot Reload in Development versus whatever things you may need in Production.

Hope this helps save you some time!


Sponsor: At Rocket Mortgage® the work you do around here will be 100% impactful but won’t take all your free time, giving you the perfect work-life balance. Or as we call it, tech/life balance! Learn more.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
November 20, 2021 13:50
Thanks, that is handy to understand.

Did you miss a final code snippet for this line?

> Let's do just wss:, only in Development. Now, if I'm using both CSPs and WebSockets (ws:, wss:) in Production, I'll need to be intentional about this.
November 22, 2021 10:08
When searching for popular search terms in Google's Keyword Planner, the two often appear bubble shooter together.
November 22, 2021 12:38
Thanks My Friend. . .
November 23, 2021 7:16
Good Afternoon

I found hanselman.com on Facebook

My name is Tomoko Auld and I am the affiliate manager at justdeltastore.com

I am writing to invite hanselman.com to join JustDelta Store Affiliate Program.

To get more information and sign up with the JustDelta Store Affiliate Program, visit https://www.affiliatly.com/af-1050770/affiliate.panel?mode=register

We look forward to seeing you on-board.

Warm Regards
Tomoko Auld
Germany, NW, Bad Driburg, 33014, Bleibtreustrasse 93, 05253 75 20 65
November 24, 2021 7:39
Hi,
I would like to thank you for sharing such factual information with us. I totally agree with all your knowledge about the full-stack development course. I know one of the online platforms that provide Full stack development courses with placement guarantees. If you are looking for full-stack development courses then you should visit the website.
November 24, 2021 10:51
Thank you very much for this post. Great
November 25, 2021 15:45
Hello

concede For You Website hanselman.com Or Affiliate Product, Use "FOREVER"!

If you are marketing a business, service, product, guide capture page, blog, we will put your site in front of rouse website visitors daily!

https://rebrand.ly/gm0bhdm

Best Regards
Alex

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.