如何使用electron.js安全地进行SQL调用。

huangapple go评论61阅读模式
英文:

How to securely make an SQL call using electron.js

问题

我正在开发一个需要查询SQL数据库的系统,它位于本地网络上,但不在同一系统上(不是SQLExpress)。

我已经成功地在网页上查询用户输入并将该信息发送到Main.JS,但我不确定查询数据库的最有效方式是什么。

我对SQL和electron.js都非常陌生,所以希望能提供更多的细节,谢谢!

以下是您提供的代码的翻译部分:

preload.js:

const invoke = (channel, args, cb = () => { return }) => {
    ipcRenderer.invoke(channel, args).then((res) => {
        cb(res);
    });
};

const handle = (channel, cb) => {
    ipcRenderer.on(channel, function (Event, message) {
        cb(Event, message);
    });
};

contextBridge.exposeInMainWorld("GlobalApi", {
    invoke: invoke,
    handle: handle
});

let get = function (path) {
    let data = dbFuncions.readSomeDatafromDB("path");
    return data;
}
contextBridge.exposeInMainWorld("myCoolApi", {
    get: get
});

renderer.js:

const { ipcRenderer } = require('electron');
const loginForm = document.getElementById('login-form');
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');

loginForm.addEventListener('submit', (event) => {
    event.preventDefault();

    const username = usernameInput.value;
    const password = passwordInput.value;

    ipcRenderer.send('login', { username, password });
});

ipcRenderer.on('login-status', (event, isSuccess) => {
    const failureMessage = document.createElement('p');
    const successMessage = document.createElement('p');
    if (isSuccess) {
        successMessage.textContent = 'Login successful';
        successMessage.style.color = 'green';
        loginForm.appendChild(successMessage);
        setTimeout(() => {
            loginForm.removeChild(successMessage);
        }, 2000);
    } else {
        failureMessage.textContent = 'Incorrect details.';
        failureMessage.style.color = 'red';
        loginForm.appendChild(failureMessage);
        setTimeout(() => {
            loginForm.removeChild(failureMessage);
        }, 2000);
    }
});

main.js:

const { app, BrowserWindow, ipcMain } = require('electron');
var Connection = require('tedious').Connection;
var Request = require('tedious').Request
var TYPES = require('tedious').TYPES;
var dbFunctions = require('sql') //我知道我在这里缺少一个函数。Stack Overflow中提到的“sql模块”

// 以下是您的配置信息,请根据需要更新这些信息
var config = {
    server: 'your_server.database.windows.net',
    authentication: {
        type: 'default',
        options: {
            userName: 'your_username',
            password: 'your_password'
        }
    },
    options: {
        encrypt: true,
        database: 'your_database'
    }
};  

var connection = new Connection(config);
connection.on('connect', function (err) {
    console.log("Connected");
    executeStatementLogin();
});

function executeStatementLogin() {
    var request = new Request("SELECT username, password FROM table_name WHERE username = ", function (err) {
        if (err) {
            console.log(err);
        }
    });

    request.addParameter('Name', TYPES.NVarChar, 'SQL Server Express 2019');
    request.addParameter('Number', TYPES.NVarChar, 'SQLEXPRESS2019');
    request.addParameter('Cost', TYPES.Int, 11);
    request.addParameter('Price', TYPES.Int, 11);

    request.on('row', function (columns) {
        columns.forEach(function (column) {
            if (column.value === null) {
                console.log('NULL');
            } else {
                console.log("Product id of inserted item is " + column.value);
            }
        });
    });

    request.on("requestCompleted", function (rowCount, more) {
        connection.close();
    });
}

function createWindow() {
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableWebSQL: true,
            preload: path.join(__dirname, 'preload.js')
        },
    });

    mainWindow.loadFile(path.join(__dirname, 'index.html'));

    mainWindow.on('closed', () => {
        mainWindow = null;
    });
}

app.on('ready', () => {
    createWindow();
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

ipcMain.on('login', (event, loginData) => {
    const { username, password } = loginData;
    console.log(`Received login request. Username: ${username}, Password: ${password}`);
    let data = dbFunctions.get(path);

    mainWindow.webContents.send(
        path,
        data
    );

    if (username == 'exampletest' && password == 'testexample') {
        isSuccess = true;
    } else {
        isSuccess = false;
    }

    setTimeout(() => {
        event.reply('login-status', isSuccess);
    }, 2000);
});

希望这可以帮助您解决问题。如果您有任何进一步的问题或需要进一步的帮助,请随时提问。

英文:

I am developing a system that requires me to query an SQL database, it is located on the local network but NOT on the same system (not SQLExpress.)

I have managed to query a user for input on the webpage and send that information to Main.JS, however I am not sure on the most effective way to query the database.

I'm very new to both SQL and electron.js, so lots of detail would be preferred, thank you!

Following other Stack Overflow questions (notably), I have:

preload.js:

const invoke = (channel, args, cb = () => { return }) => {
ipcRenderer.invoke(channel, args).then((res) => {
cb(res);
});
};
const handle = (channel, cb) => {
ipcRenderer.on(channel, function (Event, message) {
cb(Event, message);
});
};
contextBridge.exposeInMainWorld("GlobalApi", {
invoke: invoke,
handle: handle
});
let get = function (path) {
let data = dbFuncions.readSomeDatafromDB("path");
return data; // Returning the function itself is a no-no shown below
// return dbFunctions.readSomeDatafromDB("path"); Don't do this
}
contextBridge.exposeInMainWorld("myCoolApi", {
get: get
});

renderer.js:

const { ipcRenderer } = require('electron');
const loginForm = document.getElementById('login-form');
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');
loginForm.addEventListener('submit', (event) => {
event.preventDefault();
const username = usernameInput.value;
const password = passwordInput.value;
// This runs when the user submits their username and password.
ipcRenderer.send('login', { username, password });
});
// This runs when the username and password has been checked (in main.js) and a success (true) or failure (false) has been recieved.
ipcRenderer.on('login-status', (event, isSuccess) => {
const failureMessage = document.createElement('p');
const successMessage = document.createElement('p');
if (isSuccess) {
successMessage.textContent = 'Login successful';
successMessage.style.color = 'green';
loginForm.appendChild(successMessage);
setTimeout(() => {
loginForm.removeChild(successMessage);
}, 2000);
} else {
failureMessage.textContent = 'Incorrect details.';
failureMessage.style.color = 'red';
loginForm.appendChild(failureMessage);
setTimeout(() => {
loginForm.removeChild(failureMessage);
}, 2000);
}
});

main.js:

const { app, BrowserWindow, ipcMain } = require('electron');
var Connection = require('tedious').Connection;
var Request = require('tedious').Request
var TYPES = require('tedious').TYPES;
var dbFunctions = require('sql') //I know I'm missing a function here. The 'sql module' mentioned in the Stack Overflow 
const path = require('path');
let mainWindow;
var config = {
server: 'your_server.database.windows.net',  //update me
authentication: {
type: 'default',
options: {
userName: 'your_username', //update me
password: 'your_password'  //update me
}
},
options: {
// If modifying to work with Microsoft Azure (which I'm not), you need encryption:
encrypt: true,
database: 'your_database'  //update me
}
};  
var connection = new Connection(config);
connection.on('connect', function (err) {
// If no error, then good to proceed.  
console.log("Connected");
executeStatementLogin();
});
function executeStatementLogin() {
// This needs updating!
var request = new Request("SELECT username, password FROM table_name WHERE username = " + , function (err) {
if (err) {
console.log(err);
}
});
// This needs updating!
request.addParameter('Name', TYPES.NVarChar, 'SQL Server Express 2019');
request.addParameter('Number', TYPES.NVarChar, 'SQLEXPRESS2019');
request.addParameter('Cost', TYPES.Int, 11);
request.addParameter('Price', TYPES.Int, 11);
request.on('row', function (columns) {
columns.forEach(function (column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log("Product id of inserted item is " + column.value);
}
});
});
// Close the connection after the final event emitted by the request, after the callback passes
request.on("requestCompleted", function (rowCount, more) {
connection.close();
});
}
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableWebSQL: true,
preload: path.join(__dirname, 'preload.js')
},
});
mainWindow.loadFile(path.join(__dirname, 'index.html'));
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.on('ready', () => {
createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// This is old code that I made. This runs when the user clicks submit and has username and password. This could be modified to do the SQL query, too
ipcMain.on('login', (event, loginData) => {
const { username, password } = loginData;
// Here, you can perform the necessary login verification logic
// For demonstration purposes, we'll just log the username and password
console.log(`Received login request. Username: ${username}, Password: ${password}`);
let data = dbFunctions.get(path);
window.webContents.send(
path,
data
);
if (username == 'exampletest' && password == 'testexample') { //Hardcoded solution to test if ifSuccess works and the result gets sent back (which it does)
isSuccess = true
} else {
isSuccess = false
}
setTimeout(() => {
event.reply('login-status', isSuccess);
}, 2000);
});

ipcMain.on('login', (event, loginData) => is old code that I made. It has both the username and the password the user inputted already. This could potentially be modified to perform the SQL, by creating the SQL query there and executing this.

Alternatively, modifying the solution I found here which is all of preload.js and config, connection, types, dbFunctions, request and executeStatementLogin in main.js.

When I run the program, it loads, however on submit a runtime error is given. Both solutions run at the same time. My solution works fine (but does not implement SQL), and the alternative solution throws an error that dbFunctions does not have a 'get' function. This is because I do not know what the SQL module used to actually GET dbFunctions is, as it is seemingly never specified. Once I have dbFunctions, I can start to modify the code that needs to be updated (//update me), though I am not sure how I am going to modify the username and password in the config file based on user input.

Any help at all would be appreciated. Thank you! (assume I know nothing)

答案1

得分: 1

这里已经有一个类似的问题:https://stackoverflow.com/questions/47872492/electron-secure-mysql-credentials

另外,您绝对不应该将凭据嵌入到 Electron 应用程序中,因为这是绝对不安全的。您的应用程序不应直接调用 SQL 后端。

英文:

There was already a similar question here: https://stackoverflow.com/questions/47872492/electron-secure-mysql-credentials

Also, you should never ever embed credentials into the electron application, as it is absolutely insecure. You app should not be calling SQL backend directly.

huangapple
  • 本文由 发表于 2023年6月12日 17:42:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76455382.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定