Securing Your Electron App
Published: 2021-12-08 07:24:28

---
title: Securing Your Electron App
published: true
date: 2020-08-18 10:33:53 UTC
tags: 
canonical_url: https://www.turtle-techies.com/securing-your-electron-app/
---

*Written by [Andres Acevedo](https://www.turtle-techies.com/author/andres-acevedo/)*

In our <a href="https://www.turtle-techies.com/multi-platform-desktop-app-with-electron" >previous article</a>, we explored how to create a useful Electron app focusing on functionality, but leaving aside some aspects like security and platform specific features.  

In this article, we will continue from where we left, to progress in the path from a Prototype to a real world Application!  

I’d like to begin with an analogy: in healthcare studies, there's an important Latin maxim: Primum non nocere, it means:  
 "first, do no harm". Another way to state it is that, "given an existing problem, it may be better not to do something, or even to do nothing, than to risk causing more harm than good." 

If we are introducing security problems to our clients, it could be best to go back a bit (pun intended) and solve these vulnerabilities before adding new features to our pretty piece of software. 

## Working according to the warnings

So, is our app secure? If we run it with `npx electron` . and open the Developer Tools (View>Toggle Developer Tools), we can see that the console is giving us several security warnings:  

![electron showing security warnings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3sh6uh5hhptbrz4qpeug.png)

One easy way to improve our app's security is to add a special meta header to our **index.html** file:  

```html

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">

```
This instructs the Chromium rendering engine to only run local scripts.  

You can also add other allowed domains in the following way:  

```html

Content-Security-Policy: script-src 'self' https://apis.example.com

```

If you want to learn more about CSP, check:   
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP" target="_blank"> https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP </a>

Once we add that line to the header section of our website and refresh our app `(View > Reload)`, we are left with just one security warning:  

![electron showing only one security warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1sf0gpp023urv5p5n61i.png)


Getting rid of this security warning requires that we modify our `main.js` file and add the following `webPreference` to our `BrowserWindow` call:  

```javascript 

webPreferences: {
            worldSafeExecuteJavaScript: true,
            contextIsolation: true
}

```

What this does is to enforce isolation between the `Renderer World` (Chromium renderer) and Node World. This sandboxes any malicious code run from the **renderer**, reducing the possible damage of an exploited vulnerability.

Once we add the code, reloading the view is not enough - as we did changes in our `main.js` file, so we have to terminate our Electron App and relaunch it with: `npx electron` .

![electron showing console errors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjtg23omqghzqmpt0p5s.png)


> **Good news:** we got rid of the warning.  
> **Bad news:** now we have an actual error and our app does not work anymore

## Fixing the code

`Require` is a node function, and because we configured electron to separate `renderer` and node worlds, we can not use `require()` on our `renderer.js` file. 
Even if we have the `nodeIntegration: true` setting.  
In fact, let's remove that setting, so our `BrowserWindow` call in `main.js` now looks like this:

```javascript

const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      worldSafeExecuteJavaScript: true,
      contextIsolation: true,
    }
  })

```

> Electron provides us with a way to use node functions in the renderer world: **Preload scripts**.

Add the following line to `webPreferences` in our `BrowserWindow` call on `main.js`.

```javascript
preload: path.join(app.getAppPath(), 'preload.js')
```

It should look like this:

```javascript

const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      worldSafeExecuteJavaScript: true,
      contextIsolation: true,
      preload: path.join(app.getAppPath(), 'preload.js')
    }
  })

```

Don't forget to include the path module at the beginning of `main.js`:  
```javascript
const path = require('path');
```

Now let's create the `preload.js` file and write the following on it:  
```javascript

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld(
    "electron",
    {
        ipcRenderer: ipcRenderer
    }
);

```
As you can see on the first line, we can use the `require()` function in `preload.js` without problems in order to import the `ipcRenderer`. 

Now, we will remove the require line that is causing the error on the `renderer.js` file:

```javascript

const { ipcRenderer } = require('electron');

```

As we are not requiring `ipcRenderer` anymore, we can not continue using it in the same way as before. 
But that's when the `contextBridge.exposeInMainWorld` function we added on `preload.js` comes in handy.
Our `ipcRenderer` can be accessed on the `rendered.js` file by using `window.electron.ipcRenderer`.  

So it now should look like this:

```javascript

async function fileSelected(e){    
    const loadedFilePath = e.target.files[0]?.path
    let data = await window.electron.ipcRenderer.invoke('read-file', loadedFilePath)
    document.getElementById("loadedText").value = data
}
document.getElementById("fileLoader").addEventListener("change", fileSelected);

```

Result:  

![electron showing console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxhwk9yy3cxr8vqaqfsd.png)


We've made it! Our app works again and without any security warnings!

You can find the code of our Secure Text Loader on the following repo:
<a href="https://github.com/mran3/Secure-Text-File-Loader/" target="_blank"> https://github.com/mran3/Secure-Text-File-Loader/ </a>