 going to talk about the time that I got a group of friends together, and we made a secure Linux password manager. Specifically, the time we did it in Electron. So, rewind a bit. I'm Mitchell. I'm the product lead at OnePassword. I've been there for seven years and worked on a whole lot of cool projects from browser extensions to desktop apps. And the latest thing I built is a new OnePassword app for Linux. And personally, I'm a security adjacent person. I'm not a security guy myself, but I work at a security company. But I spend a lot of time talking to them, getting to know how they think, and device versa. So I hope to distill some of that today to an audience of security people. So a bit about OnePassword for Linux. It's our newest app. It's beautiful. It's fast. It has so many features. And it just came out yesterday, actually, so really good timing. And I hope everyone has a chance to go check it out. And from an architecture standpoint, it's actually a pretty fascinating app in that we call it a hybrid app, because it's kind of got two halves. One half is a back end that's entirely native and written in Rust and sort of does all the series of business logic. And the front end, of course, is written in Electron. And that serves as our view layer uses the web stack. But if you make a talk called how to harden your Rust app, it's not as clickbaity and not as many people care. So that's why we're here today to talk about the part that everyone wants to know about the features for, and that's the Electron front end. But before we can do that, we have to actually explain what an Electron app even is, because they're pretty popular for better or worse. They're all over our computers. I guarantee everyone watching this has one open right now in front of them, probably more than one in their doc. But what exactly are they and why aren't they secure? Or at least, why do we think they're not secure? So an Electron app is a web app. That's kind of the answer people give when you ask them, what's an Electron app? It's just a web app. And we all know the problems with web apps. And I can see why people think this way, because this is Slack. Actually, this is two Slack's. And one of them is open in my web browser. The other one is open in, well, the Slack app. And they look like the same app. So you can see, well, someone just took the web app and put it sort of in a window and called it a day. And that's an Electron app. But it probably is more accurate to say that an Electron app is not a web app. It's a web browser. And I don't know if that makes anyone feel better, because it shouldn't. Every time you make a web browser, every time you make an Electron app, you're making the same thing. Specifically, you're taking Chromium and you're forking it. And if we didn't have enough Chromium forks in the world, Electron is just making it easier for people to make new ones. But it's not just a web browser. An Electron app is also a Node.js app. And if you haven't used Node.js before, it's pretty cool. It lets you basically take JavaScript out of your web browser and write it on your desktop. And you can do all sorts of fun things. You can import like an awesome C library. Or you can write some data somewhere at a desk without really worrying about it. You can even open shell commands with whatever input you feel like. So it's a pretty powerful, fun, and secure way to write apps, of course. But an Electron app isn't just a Node app. It's also a native app. And that's where things get interesting, because it's a native app, of course, in that it runs on your desktop system. But it doesn't just contain your native code. It actually contains all sorts of libraries and binaries that you didn't write, that you didn't compile. And there's some really cool stuff in there. There's like lib.fm.bag. And I think there's like an Xbox 360 controller. We haven't had a reason, drivers, we haven't had a reason to actually use that in our app yet, but it's there if you want it. So there's a lot going on inside of an Electron app. And each of these sort of things, they all have their own security concerns, they have their own best practices, they have their own problems that we have to solve. But the biggest problem is that they're not just isolated, they all talk to each other. And they communicate in ways that sort of violate the security expectations of each other, right? How do you make a secure web app that can talk to Node, that can talk to Chromium, that can talk to a native app? It's kind of exponentially more difficult. And that's kind of the problem we have to solve when we make an Electron app. So let's go do that. Let's make it secure. Or rather, let's make it secure enough for our purposes, which to be honest is any security challenge, it's about sort of making sure that you meet your specific security goals. So to do that, we want to do just a bit of threat modeling. And there are a lot of ways to do this, of course. But again, I'm not a security guy, I'm sort of a product person. So I'm going to think about the specific business goals of our product, one password, which is to be basically a zero knowledge repository for secrets. We guarantee to our customers that their secrets are inaccessible to anyone but them, or rather anyone who does not possess the keys to those secrets. And that means both local and remote. So that's a big promise. So how is that going to line up with the environment? Well, the answer is not very well. Electron is a bit of a leaky faucet. It has all these immediate threat vectors that we can think of that allow people to leak all sorts of things in and out. And we don't even know if we have sort of a comprehensive list. So we have to do a lot to make sure that we can actually deliver our business goal through our app in this environment. So we need a plan. And my plan is going to have three parts to it. The first thing we're going to do is we're going to take this app offline. Then we're going to take away node. And then finally, we're going to take the rest of it native. And I'm going to go into detail about exactly how we do all three of these things and why they're important. So let's take it offline. So what I mean by that is we're going to use bundle code only. We are not going to allow any kind of navigation. And we're just going to disable all the browser stuff we can find. Why do we need to take this app offline? It's because the web is basically a multiplayer programming environment where anyone across the world can write code on each other's computers for better or worse. And you can be browsing a perfectly safe website, but if the developers slip up, suddenly someone hacks it and it's a Pokemon emulator. And to be honest, I really like Pokemon, but I don't want people to be able to inject it into my secure password manager. So what can we do about that? Well, we can take advantage of the best feature of Electron, which is that, yes, it allows you to sort of use a web app, but you can deliver it the way you would deliver a desktop app. You can deliver it offline as part of the bundle. And that is huge for us. And that's the most important thing to do because what it lets us do is a couple of things. First, we can use an incredibly strict content security policy, basically a script source self. And that is going to just lock down remote code execution. It's going to prevent XSS and Aval. And it's going to stop people from injecting all sorts of weird things into our web app. But beyond that, we get to take advantage of native mechanisms for protecting apps, like package signing and code signing. And I mean, compared to TLS and SSL, this is a great way to make sure that no one can get into your app on its way to the consumer. And unfortunately, code signing isn't available on Linux, but hopefully it will be one day. Any desktop Linux advocates, please, please push for this, because I'd really love it. But that's not the only problem with this app. It's not just a web app, it's a web browser. And web browsers do one thing really well, which is they browse the web. If you look at sort of the UI of a web browser, like all these buttons take you places, and hopefully you're not actually building a web browser in your electron app. And if you are, please, please don't, we have enough of them. But if you aren't, you really don't want these things because even if you've used your strict content security policy and put a lot of effort into it, like all someone has to do is navigate and suddenly, you know, your beautiful app is Pokemon again and you didn't want that, hopefully. So we're gonna turn all that off. We're gonna disable all the navigation events that we can find. And to be honest, there are a number of them and they're kind of all over the place. But if you sort of read the docs and do enough work, you can find them and you can turn them off and you can make sure that your app stops behaving like a web browser when you don't want it to. So that's pretty good, but there's another problem with web browsers and especially for our app, the problem is that they kind of remember everything you do and they do that on purpose, right? They keep history, they keep caches of images, they keep your authentication sessions, they build up gigabytes of sort of stuff to help you out later. And that again, goes against our policy of being zero knowledge. So we have to sort of get on top of that and Electron actually does give us the tools to do this by allowing us to make a custom session. So every Electron app comes in sort of a default browser session, but we don't have to use it, we can make our own. And if we do that, that's gonna give us direct control over what kind of caches we create, how we handle permission requests, how and when we store data and when we clear it. So I mean, every app's gonna have different requirements here, but it's best to be explicit and to sort of manage that directly. And if you want to, you can even use this to create basically your own version of incognito mode, where the app doesn't remember anything that the user does in the session. And I mean, if your app's going to be a web browser, you might as well take the best feature of web browsers for privacy and security and take advantage of it. So that's what we're gonna do. So we've put in a bit of work already to make our web app secure and to make the web browser part secure. But once you've done that, you're gonna feel good and then you're gonna start hearing sort of voices in your head and they're gonna say things to you. They're gonna whisper like, hey, do you wanna turn on some node integration? No, you sure? Maybe you just wanna use the remote model. It's safe, I promise. And you're gonna be really tempted by these voices. And the reason you're gonna be tempted is because what Electron is trying to do is it's trying to give you access to Node.js. So remember I said that every Electron app has Node.js built in. And that's really cool. Like Node.js has a lot of features that can really make your app more powerful. Things that web apps can't do, like write files and run commands. But the way Electron tries to get you to use Node.js is not very safe because this is what it looks like when you have node integration on in your Electron app. So your web content sort of is down in the right corner and Node.js can directly access it and vice versa. They have a bi-directional connection. And that's really dangerous because web app security just isn't designed to assume that it has access to system APIs and there's really no way to lock that down. So what if we just turn Node integration off? Which is what the Electron docs recommend. Well, unfortunately it looks like we haven't really accomplished anything because Node.js no longer has access to the HTML content on your page but it still goes through this thing in the middle called preload.js and it looks like there's a line going all the way across and they can still talk to each other. So you've done all this work, you read the docs and someone can still inject a Gameware emulator into your app and you haven't accomplished anything. So we got to do more than that. And the first thing we have to do is understand the dangers of this thing called preload.js. So it's kind of a script that gets injected from your Electron app into every web page inside of it. And it's pretty dangerous because it lets you put whatever you want on the DOM inside of your web app. And whatever you want includes like whatever Node APIs you feel like. So it's a pretty bad idea to be honest and preload scripts just are arguably like the worst part of Electron. So the solution might be simple, let's just get rid of the preload script and then they can't talk to each other. But in a sense like that kind of defeats the point of Electron, like I wrote this awesome C-lib and I want my web app to be able to take advantage of it. So what am I going to do if they can't talk to each other? And the good news is that modern versions of Electron do have a solution to this problem or several. The first one and the one I really love is Sandbox and it's actually not on by default yet but hopefully it will be in future version of Electron. What it does is it actually sandboxes your renderer so that you can't just use Node.js inside of it. You have to use an IPC API to be able to talk to Node.js. You can't directly get access to it. So that one's really powerful and it saves you and it saves you from accidentally letting like whatever commands you want into your web content. And to go along with the Sandbox, you have this great tool called Context Isolation which again is fairly new and I think will be made default at some point and that lets you sort of expose like a safe API to your web content. That it has to be like a static API. It can't be like a fancy runtime object. It can't have all sorts of functions and that'll make sure that your web content can't call anything that you don't know about and can't get direct access to Electron or Node APIs that could trash your system. So if you use these two together, you have this really nice setup where you have a one way connection between the preload script and your web content through the Context Isolation and both of them are inside of a Sandbox so you can't directly run Node even inside of your preload script. So it adds a bit of an IPC cost but basically like I consider this mandatory if you're not architecturing your Electron app this way, you're gonna run into problems. So we've put Node in its place and hopefully dealt with that problem. And the thing is we should take advantage again of the fact that an Electron app is actually native. So instead of writing sort of all of our critical and security sensitive business logic inside of Electron, inside of the web app, let's put them inside of a native module and link it up. So that's basically exactly what we did but again, it's 2021. So we're not gonna link to Awesome C-Lib. We're gonna write it in Rust because we're cool like that. So we're using Awesome Rust Lib. And specifically, this is kind of an architecture diagram of One Basterd for Linux. And you can see that we actually wrote effectively a headless One Basterd client in Rust and just sort of hooked it up to the front end over in FFI. And it was a really great architecture. It's worked out well so far. And we did it with this wonderful tool called Neon. Neon is a project, it's maturing rapidly. Like when we started using it, it didn't do everything we need, but now it does. It provides these sort of safe declarative bindings between a Node app and a native Rust app and lets you do this in a way that it's not going to introduce you to security problems. So we were really happy with it and we thought we were done. So we went to our internal security people and asked for an audit. And unfortunately, we got a CVE, an internal CVE from our audit. And it was confusing. The issue said that we weren't doing any validation of our authentication URLs. And that's a pretty serious problem, right? And we were confused by that because the first thing we had done with this app was we used a strict content security policy, which by definition doesn't let you connect to any URL. But the problem was that we had gone and reimplemented networking in our native Rust app. And that part didn't know about content security policies. So we thought we were sort of being safer inherently by using Rust, but like you got to watch out just because you're using Rust and you're making a native component doesn't mean it's secure by default. You still have to know about the security model and design of that component and whatever you do inside of the web component doesn't actually help you here. So that's something we sort of learned in the hard way. Luckily, we learned it before we shipped. So now we finally thought we were done, but Electron had one more trick up at sleep, one more thing we needed to deal with. And that is going all the way back to when I said that an Electron app is actually not just a Node app, it's someone else's native app. And that native app comes with features that you have to learn about because like they exist in your app when you ship it. It comes with command line switches. It comes with all sorts of controls that people can deliver to the app that you didn't write. And some of them are pretty sketchy. Like you can control the garbage collector. You can set up like debug ports. You can do all sorts of things. The Node.js documentation lets you do. And I don't have time to read that. So I just want to turn all this stuff off. And luckily Electron does let you do that with this feature called fuses. It's not too well documented unfortunately, but basically fuses are, they call them magic bits in Electron that you can flip off when you package the app. And that's going to turn off sort of all these little connections to Node that you don't need. Like we turn them all off because we don't need any of them. But actually doing this is a bit hard. And it's not, again, it's not that well explained. So what we did to make it easier was we wrote a tool called Electron Hardener which will basically go through your Electron binary and flip off all these switches for you and you can figure it. And it's written in Rust, it's by Christian Rask who is a security engineer at OnePassword. And we would love for people to check it out and to use it because honestly it's just going to, it's going to save you a lot of time and a lot of surprises hopefully in the future. So the bottom line is that it's not impossible to make a secure Electron app. And more importantly, it's necessary because these apps are all over our system and we're using them all day. So we might grumble, but we have to understand, where the weak points are and establish best practices. And these best practices, like I said, are going to be different from the typical best practices for web apps or even for desktop apps. But to make it easier, there are some resources you can use to sort of save you a lot of this effort. So the big one is this wonderful tool called Electronegativity which I started using sort of way back when we started. And what it does is you run it in CI basically and it tells you what you've done wrong. So like if you left a navigation event exposed, it'll tell you. If you don't have a strict CSP, it'll tell you. And you can basically go through it like a checklist and it'll help you get your app into a pretty secure state automatically using static analysis. And it's by DorianSec and in fact, they gave a great talk at Black Hat a few years ago that goes really deep into the architecture of Electron and its security risks. And if you are making an Electron app yourself, I recommend you check out that talk as well. And then finally, there's a tool that we made or rather a repository called Electron Secure Defaults which kind of takes everything we've learned and puts it all together and annotates it. And I'd invite people to check that out too. It is in fact the Electron configuration that we're using in One Basterd for Linux. And we want to both help people make their own app secure but to be honest, we also want to know if we've missed anything. Because again, the surface area is rather large and these things are all sort of being discovered by the community as we go. So anything we can do to make our app even safer is better for us and better for everyone. And the last place you should check or arguably the first place is the actual official Electron documentation. Electron, despite all the snark does care about security. They put a lot of effort into it, especially in the past few years and they do have great documentation about many of the things I talked about and how to use them and get the most out of them. So hopefully they'll sort of make a bit of it on by default because I think that's the biggest shortcoming right now where you have to switch on these things that help you but if you didn't know about them you're gonna be in a bad state. But I do appreciate all the documentation and all the work that they're doing. And with all that in mind, you can make a pretty secure Electron app or at least secure enough.