mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-19 07:16:01 +00:00
SYNC: security fixes
This commit is contained in:
committed by
Diflow
parent
3f37b2b728
commit
cf3f95c952
@@ -12,6 +12,7 @@ const getMapExport = require('../utility/getMapExport');
|
||||
const dbgateApi = require('../shell');
|
||||
const { getLogger } = require('dbgate-tools');
|
||||
const platformInfo = require('../utility/platformInfo');
|
||||
const { checkSecureFilePaths, checkSecureDirectories } = require('../utility/security');
|
||||
const logger = getLogger('files');
|
||||
|
||||
function serialize(format, data) {
|
||||
@@ -26,25 +27,6 @@ function deserialize(format, text) {
|
||||
throw new Error(`Invalid format: ${format}`);
|
||||
}
|
||||
|
||||
function checkSecureFilePaths(...filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
if (filePath.includes('..') || filePath.includes('/') || filePath.includes('\\')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkSecureDirectories(...filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
const directory = path.dirname(filePath);
|
||||
if (directory != filesdir() && directory != uploadsdir() && directory != archivedir() && directory != appdir()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
list_meta: true,
|
||||
async list({ folder }, req) {
|
||||
|
||||
@@ -19,6 +19,7 @@ const {
|
||||
const { handleProcessCommunication } = require('../utility/processComm');
|
||||
const processArgs = require('../utility/processArgs');
|
||||
const platformInfo = require('../utility/platformInfo');
|
||||
const { checkSecureDirectories, checkSecureDirectoriesInScript } = require('../utility/security');
|
||||
const logger = getLogger('runners');
|
||||
|
||||
function extractPlugins(script) {
|
||||
@@ -273,6 +274,12 @@ module.exports = {
|
||||
const runid = crypto.randomUUID();
|
||||
|
||||
if (script.type == 'json') {
|
||||
if (!platformInfo.isElectron) {
|
||||
if (!checkSecureDirectoriesInScript(script)) {
|
||||
return { errorMessage: 'Unallowed directories in script' };
|
||||
}
|
||||
}
|
||||
|
||||
const js = await jsonScriptToJavascript(script);
|
||||
return this.startCore(runid, scriptTemplate(js, false));
|
||||
}
|
||||
@@ -317,6 +324,11 @@ module.exports = {
|
||||
|
||||
loadReader_meta: true,
|
||||
async loadReader({ functionName, props }) {
|
||||
if (!platformInfo.isElectron) {
|
||||
if (props?.fileName && !checkSecureDirectories(props.fileName)) {
|
||||
return { errorMessage: 'Unallowed file' };
|
||||
}
|
||||
}
|
||||
const prefix = extractShellApiPlugins(functionName)
|
||||
.map(packageName => `// @require ${packageName}\n`)
|
||||
.join('');
|
||||
|
||||
52
packages/api/src/utility/security.js
Normal file
52
packages/api/src/utility/security.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const path = require('path');
|
||||
const { filesdir, archivedir, uploadsdir, appdir } = require('../utility/directories');
|
||||
|
||||
function checkSecureFilePaths(...filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
if (filePath.includes('..') || filePath.includes('/') || filePath.includes('\\')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkSecureDirectories(...filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
if (!filePath.includes('/') && !filePath.includes('\\')) {
|
||||
// If the filePath does not contain any directory separators, it is considered secure
|
||||
continue;
|
||||
}
|
||||
const directory = path.dirname(filePath);
|
||||
if (directory != filesdir() && directory != uploadsdir() && directory != archivedir() && directory != appdir()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function findDisallowedFileNames(node, isAllowed, trace = '$', out = []) {
|
||||
if (node && typeof node === 'object') {
|
||||
if (node?.props?.fileName) {
|
||||
const name = node.props.fileName;
|
||||
const ok = isAllowed(name);
|
||||
if (!ok) out.push({ path: `${trace}.props.fileName`, value: name });
|
||||
}
|
||||
|
||||
// depth-first scan of every property / array index
|
||||
for (const [key, val] of Object.entries(node)) {
|
||||
findDisallowedFileNames(val, isAllowed, `${trace}.${key}`, out);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function checkSecureDirectoriesInScript(script) {
|
||||
const disallowed = findDisallowedFileNames(script, checkSecureDirectories);
|
||||
return disallowed.length == 0;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkSecureDirectories,
|
||||
checkSecureFilePaths,
|
||||
checkSecureDirectoriesInScript,
|
||||
};
|
||||
Reference in New Issue
Block a user