ElectronNET / Electron.NET

:electron: Build cross platform desktop apps with ASP.NET Core (Razor Pages, MVC, Blazor).
https://gitter.im/ElectronNET/community
MIT License
7.26k stars 724 forks source link

Security considerations #22

Open robertmuehsig opened 6 years ago

robertmuehsig commented 6 years ago

Twitter discussion - currently we launch a plain webserver on localhost. Maybe we could avoid to launch a "real" webserver at all, see here:

https://twitter.com/robert0muehsig/status/924741177525587968

damianh commented 6 years ago

In a previous incarnation of sort of the same thing (but windows only), it was possible to hook into chrome, register a scheme and have the handler take the request and directly invoke it against the pipeline.

https://github.com/eVisionSoftware/Harley/blob/master/src/Harley.UI/MainWindow.xaml.cs#L23 https://github.com/eVisionSoftware/Harley/blob/master/src/Harley.UI/Owin/OwinSchemeHandlerFactory.cs#L44

I'd be really surprised if there wasn't an equivalent hook in Electron.

The hard part is probably hosting the .net code / clr in the same process. Definitely done elsewhere, but beyond my knowledge at this point.

Wondering if edge.js has anything useful to lift?

damianh commented 6 years ago

Well hello

https://github.com/tjanczuk/edge/blob/master/src/CoreCLREmbedding/coreclrembedding.cpp

robertmuehsig commented 6 years ago

Nice one - I guess currently our priorities would be to work on some basics, like easier debugging support or actual better build support (Icons for the produced app etc.), but I'm really interested in doing this 👍 (or if you have some sparetime - just sent a PR 😃 )

ghost commented 6 years ago

A big step. Hosting the .net code / clr in the same process is a great feature.

raffaeler commented 6 years ago

My xcore plugin for nodejs can smoothly call any netstandard assembly from nodejs (even async stuff) [in-proc of course] without having to do nothing for the interop (I do generate the required code on the fly) and allows to call almost any method/property/indexer/event/ctor. Could this be of any help?

robertmuehsig commented 6 years ago

Sure - do you have a GitHub Repo for your code?

raffaeler commented 6 years ago

The repo just contains the user guide and a couple of videos explaining how it works, but no sources yet. https://github.com/raffaeler/xcore

I published the plugin here: https://www.npmjs.com/xcorenode

There are few things that are worth to say:

  1. I am going to change the C++ part heavily in order to adopt N-API which is the nodejs API which should not require to recompile the plugin for each nodejs version
  2. I could use it from the standard Electron but in certain cases Electron crashes. Looking with windbg the crash, it does not depend on my plugin but noone (in chat or on github) from Electron helped me to understand the issue.
  3. I am also improving the perf in the netcore side of the plugin
  4. Part of the plugin is already x-plat (like for example loading coreclr) but I still have to adjust few other things to make it entirely work on linux.

If you have other questions, please let me know

robertmuehsig commented 6 years ago

@raffaeler Is XCore/XCoreNode similar to Edge.js but works with .NET Core?

raffaeler commented 6 years ago

I like to say that is more than that. Edge.JS impose a fixed signature for the method to be called while xcorenode leave the .net developer free to shape the class at her will. Also, Edge.JS limit to methods while I allow ctos/props/methods/events, even with overloads (that were pretty difficult to implement). The setup is also simpler. When I initially tried to use Edge.js, I had several troubles. Instead I opted for a "self-contained deployment" so that all the required .net binaries are available and part of the plugin. You can take a look to the npm package javascript examples to see the supported features.

Anyway, Edge.js is more mature and targets more than just .net interop, therefore please don't take my words as a critic towards Edge.js.

yoDon commented 6 years ago

I like the idea of trying to internalize the webserver but it would be great to maintain the option of exposing the webserver when desired (I'm working on a project where I absolutely do want the webserver reachable from other processes running on the machine)

GregorBiswanger commented 6 years ago

I have an idea with an own web proxy, which can not listen with Fiddler or an other HTTP Debugger.

The next idea is to allow only requests from electrons chromium browser.. It's not the best and I need help to create the web proxy with .net core..

We can give an additional option to deactivate some new security parts...

raffaeler commented 6 years ago

@GregorBiswanger I don't get your goal. If you want to disable people sniffing the page, it's useless. I wrote a driver that can capture even localhost (which is "short-circuited" and is not processed from the whole network stack). From a security perspective, once you are admin of the local machine, the game is over.

GregorBiswanger commented 6 years ago

@raffaeler Yes, that is true. But every Electron application and local desktop application is not secure.. (reverse engineering etc.).. I think this steps are important to have a little better security.. protection of kiddy crackers :)

That is only an idea.. at the end the community should decide too..

I'm happy about other ideas too...

raffaeler commented 6 years ago

@GregorBiswanger just use https for internal communication then. Again, you can decrypt the channel if you know how to retrieve the private key of the certificate but there will always be a way to sniff what the process is doing. This is no different than any other desktop app. You can use spy++, windbg, APImon, or whatever else tool to watch the process activity in detail. And even UWP is no different, sandboxes are done to avoid exiting the sandbox, but you can easily inject code there ... this is one of my demos ;-)

GregorBiswanger commented 6 years ago

@raffaeler yeah.. thats right.. and the problem with certificate is, it expires..

The common question here is.. should we invest to the lightweight security implementations? (proxy, https etc.)

raffaeler commented 6 years ago

@GregorBiswanger you can create a self-signed lasting 100 years :) From a security perspective you should just use the services offered from the OS. Tokens, integrity levels and ACLs are the most common tools to avoid major issues from the other processes. But once you run as admin on the box, the game is over :)

yoDon commented 6 years ago

At the risk of proposing a "big idea" change, if your front end is a so-called single page app that gets delivered to the browser as a single chunk of HTML and a single bundle.js, then Electron's built-in Ipc functions means you can get all the benefits of running C# on the server without actually needing to run or expose ASPNET on the C# side.

The React sample I made (https://github.com/yoDon/Electron.NET-React-Typescript-MobX) maintains the full ASPNET MVC server in case someone wants to use the MVC capabilities, but it doesn't actually use any of it even while maintaining full C# state and functionality to back up the app. I added one class in /Ipc/Register.cs that registers all the Ipc routes. The register function is called by the ElectronBootstrap() function which is part of Configure(...) in Startup.cs. End result is I have the full Javascript/Typescript frontend UI experience and the full C# backend experience and no actual ASPNET functionality being used or needed anywhere in the process.

Like I said, that's a pretty "big idea" shift in how Electron.NET is used, but I think it's (a) more secure because it doesn't expose any ports and (b) the "right" way to do this sort of single-page application, without needing to do a ton of server work to regenerate all the static HTML repeatedly. React (and libraries like it) basically solved that problem for us. Build the HTML and bundle.js in advance, load it into the browser/renderer, and then everything after that is just exchanging function calls and json blobs with the server, which is what Ipc was built for.

Note I'm not proposing anything that would break compatibility with ASPNET (as I said, my sample maintains the full ASPNET stack and even loads an index.cshtml needlessly on launch just to prove it maintains the compatibility, even though it doesn't need it). If you really need ASPNET, use it, but I think for a very large numbers of use cases Ipc will handle 100% of what ASPNET would have been used for, without exposing any ports or enlarging the size and perf cost of the delivered applications.

UPDATE: We should confirm that ASPNET isn't being used behind the scenes to serve up my /wwwroot/index.html and /wwwroot/bundle.js files. That's a pretty tiny amount of surface area, and is stuff that the underlying Electron tech can clearly easily handle, but I'm realizing I haven't actually checked whether it's Electron or ASPNET that's handling serving up those two files at present.

robertmuehsig commented 6 years ago

AFAIK this line makes sure that wwwroot is exposed to Electron, so you make use of ASP.NET.

Even if we don't expose a ASP.NET Core Service to Electron, we still need the IPC communication going on, right?

yoDon commented 6 years ago

Definitely need the IPC. When I first started looking at all this, I figured wtf is this IPC thing, I want "real" tech like SignalR, but then as I better understood what what going on I realized that IPC really is the right way to communicate between the two processes because it's a low-level direct pipe that's not exposed to the rest of the OS.

The way you have IPC and hosting of dot net integrated into Electron.NET is the magic that's the key to all this wonderful goodness.

robertmuehsig commented 6 years ago

Wild idea to skip the ASP.NET stuff completly (at least for the "builded" app) : It would be possible to xcopy the wwwroot files to the electron dir, which will be packed, then we just need to boot up a .net core console application with the IPC stuff for the "backend".

Development/debugging might be "harder", but could work.

yoDon commented 6 years ago

I'm pretty sure that Electron already supports hot reloading of the HTML/JS, so if you tweak the source JS files it would automatically do the transpiling/webpacking/loading/refreshing etc on the fly as you type in your editor. It's pretty slick stuff.

yoDon commented 6 years ago

<- Technically the "it" that I referred to about would be webpack that's watching the filesystem and regenerating the code and such (I have all that running now in my boilerplate, the /wwwroot/bundle.js files will auto regenerate as you change the source files, but my HTML isn't configured yet to hot-load the updated bundle.js files (I think that's a pretty straight forward thing to do on the npm/HTML side, I just haven't gotten to it yet)

robertmuehsig commented 6 years ago

Mhhh... so you suggest we should just host the IPC stuff inside the actual .NET Core process?

yoDon commented 6 years ago

I'm WAY less knowledgable about the dotnet core internals than you guys are but I think that's what I'm suggesting. Then you'd still be able to host ASPNET if you wanted to but it wouldn't be a required part of the process. You'd just need some way to tell Electron to host the files that are currently thought of as the /wwwroot contents if you were to make ASPNET optional.

ghost commented 6 years ago

@yoDon HI I saw this line https://github.com/ElectronNET/Electron.NET/blob/200f51194062a953e1924c309e4de65941f2119b/ElectronNET.API/BridgeConnector.cs#L21 and this https://github.com/ElectronNET/Electron.NET/blob/200f51194062a953e1924c309e4de65941f2119b/ElectronNET.API/IpcMain.cs#L49 It seem like ElectronNET.API.IpcMain base on socket. It isn't realy ipc. Am I right?

yoDon commented 6 years ago

@konding all I know is the "IPC" terminology comes from how atom and Electron talk about their code. I'm not sure if the ElectronNET bits are implemented the same way as the base Electron IPC but @robertmuehsig or @GregorBiswanger probably know

robertmuehsig commented 6 years ago

Mhh... the communication path is described here. Our Electron.NET talks via this Socket to the Electron stuff.

I'm not sure what the definition of IPC is, but we use http as the channel. At work we are using named pipes to do IPC, but we just run on Windows. What is your definition of IPC @konding ?

ghost commented 6 years ago

My understanding is two objects communicate with each other in the same process. @robertmuehsig

raffaeler commented 6 years ago

FYI I could solve the issues of my plugin with Electron. It was not a real bug, but both me and Electron used a "slot" so each of us was overwriting the other. Anyway, I could successfully run C# code inside the renderer process. I still have no public releases. BTW, if anyone of you is at the next mvp summit, I will be there and we can chat about it.

robertmuehsig commented 6 years ago

@raffaeler Then we shall meet at the summit :) @GregorBiswanger

raffaeler commented 6 years ago

You can bet! :) My handle here is the same on twitter.

nathanwienand commented 3 years ago

I have added the build parameter to /p:PublishSingleFile true in my recent PR. I have a version of blazor webassembly, with host running in Electron.NET, bundled as single .exe file.

The only code exposed is .wasm file, so disassembly is not as easy as dropping DLL's into ILSpy or DotNetPeek anymore. Also the app doesn't ship with any dll's this way. just a single .exe

domialex commented 3 years ago

If some people are strictly concerned about security, here's something I did for my project: https://github.com/domialex/Sidekick/commit/6a9f7bf5d9cc6839003bd00ab3541bef22f2685a

Important parts are the await browserWindow.WebContents.Session.Cookies.SetAsync(electronCookieProtection.Cookie); and the ElectronCookieProtectionMiddleware.

I just added a cookie with a Guid generated on startup to the BrowserWindow, then a middleware that verifies it on every request. Works perfectly.