Securing SQLite3 Data in ElectronJS: Persistent and Protected Database Storage
Saving details in SQLite3 in an ElectronJS application and securing the database file can be approached in a few steps. Here’s a comprehensive guide to achieve this:
1. Setting Up SQLite3 in Electron
First, you'll need to install the sqlite3
package and integrate it into your Electron application.
bashCopy codenpm install sqlite3
npm install --save-dev electron-rebuild
Run electron-rebuild
to ensure compatibility:
bashCopy code./node_modules/.bin/electron-rebuild
2. Creating and Using the SQLite Database
Here's an example of how to set up and use an SQLite database in your Electron application:
main.js
javascriptCopy codeconst { app, BrowserWindow } = require('electron');
const path = require('path');
const sqlite3 = require('sqlite3').verbose();
let db;
// Initialize the database
function initDatabase() {
const dbPath = path.join(app.getPath('userData'), 'database.sqlite');
db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error('Error opening database', err);
} else {
db.run('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)');
}
});
}
// Create the main window
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
mainWindow.loadFile('index.html');
}
// Initialize the app
app.whenReady().then(() => {
initDatabase();
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('before-quit', () => {
db.close();
});
preload.js
javascriptCopy codeconst { contextBridge } = require('electron');
const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const dbPath = path.join(require('electron').remote.app.getPath('userData'), 'database.sqlite');
const db = new sqlite3.Database(dbPath);
contextBridge.exposeInMainWorld('api', {
addUser: (name, email) => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)', [name, email], (err) => {
if (err) {
console.error(err.message);
}
});
},
getUsers: (callback) => {
db.all('SELECT * FROM users', [], (err, rows) => {
if (err) {
console.error(err.message);
callback([]);
} else {
callback(rows);
}
});
}
});
3. Securing the Database
To secure the database file, you can:
Store it in a Protected Location: Place the database file in a directory that is less accessible to users. For example, you can store it in
app.getPath('userData')
.Encrypt the Database: Use an SQLite encryption extension like
sqlcipher
to encrypt the database file.
4. Preventing Database Reset on Update
When you update the software, ensure that the userData
directory is not overwritten. This is the default behavior for Electron applications, but it's important to confirm:
- User Data Directory: The
app.getPath('userData')
is designed to persist data across application updates.
5. Encrypting the Database with sqlcipher
Here’s how you can use sqlcipher
:
bashCopy codenpm install sqlcipher
npm install --save-dev electron-rebuild
./node_modules/.bin/electron-rebuild
main.js
javascriptCopy codeconst sqlite3 = require('sqlite3').verbose();
const SQLCipher = require('sqlcipher');
const dbPath = path.join(app.getPath('userData'), 'secure_database.sqlite');
const db = new SQLCipher.Database(dbPath);
db.serialize(() => {
db.run("PRAGMA key = 'your_secure_key';");
db.run('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)');
});
Conclusion
By following these steps, you can create a secure SQLite3 database within your Electron application, ensuring that it persists across updates and is protected from unauthorized access.