refactor: Add new Parse Server option fileUpload.fileExtensions to restrict file upload by file extension (#8539)
This commit is contained in:
@@ -465,6 +465,11 @@ export class Config {
|
||||
} else if (typeof fileUpload.enableForAuthenticatedUser !== 'boolean') {
|
||||
throw 'fileUpload.enableForAuthenticatedUser must be a boolean value.';
|
||||
}
|
||||
if (fileUpload.fileExtensions === undefined) {
|
||||
fileUpload.fileExtensions = FileUploadOptions.fileExtensions.default;
|
||||
} else if (!Array.isArray(fileUpload.fileExtensions)) {
|
||||
throw 'fileUpload.fileExtensions must be an array.';
|
||||
}
|
||||
}
|
||||
|
||||
static validateIps(field, masterKeyIps) {
|
||||
|
||||
@@ -975,6 +975,13 @@ module.exports.FileUploadOptions = {
|
||||
action: parsers.booleanParser,
|
||||
default: false,
|
||||
},
|
||||
fileExtensions: {
|
||||
env: 'PARSE_SERVER_FILE_UPLOAD_FILE_EXTENSIONS',
|
||||
help:
|
||||
"Sets the allowed file extensions for uploading files. The extension is defined as an array of file extensions, or a regex pattern.<br><br>It is recommended to restrict the file upload extensions as much as possible. HTML files are especially problematic as they may be used by an attacker who uploads a HTML form to look legitimate under your app's domain name, or to compromise the session token of another user via accessing the browser's local storage.<br><br>Defaults to `^[^hH][^tT][^mM][^lL]?$` which allows any file extension except HTML files.",
|
||||
action: parsers.arrayParser,
|
||||
default: ['^[^hH][^tT][^mM][^lL]?$'],
|
||||
},
|
||||
};
|
||||
module.exports.DatabaseOptions = {
|
||||
enableSchemaHooks: {
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
* @property {Boolean} enableForAnonymousUser Is true if file upload should be allowed for anonymous users.
|
||||
* @property {Boolean} enableForAuthenticatedUser Is true if file upload should be allowed for authenticated users.
|
||||
* @property {Boolean} enableForPublic Is true if file upload should be allowed for anyone, regardless of user authentication.
|
||||
* @property {String[]} fileExtensions Sets the allowed file extensions for uploading files. The extension is defined as an array of file extensions, or a regex pattern.<br><br>It is recommended to restrict the file upload extensions as much as possible. HTML files are especially problematic as they may be used by an attacker who uploads a HTML form to look legitimate under your app's domain name, or to compromise the session token of another user via accessing the browser's local storage.<br><br>Defaults to `^[^hH][^tT][^mM][^lL]?$` which allows any file extension except HTML files.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -540,6 +540,9 @@ export interface PasswordPolicyOptions {
|
||||
}
|
||||
|
||||
export interface FileUploadOptions {
|
||||
/* Sets the allowed file extensions for uploading files. The extension is defined as an array of file extensions, or a regex pattern.<br><br>It is recommended to restrict the file upload extensions as much as possible. HTML files are especially problematic as they may be used by an attacker who uploads a HTML form to look legitimate under your app's domain name, or to compromise the session token of another user via accessing the browser's local storage.<br><br>Defaults to `^[^hH][^tT][^mM][^lL]?$` which allows any file extension except HTML files.
|
||||
:DEFAULT: ["^[^hH][^tT][^mM][^lL]?$"] */
|
||||
fileExtensions: ?(string[]);
|
||||
/* Is true if file upload should be allowed for anonymous users.
|
||||
:DEFAULT: false */
|
||||
enableForAnonymousUser: ?boolean;
|
||||
|
||||
@@ -140,6 +140,38 @@ export class FilesRouter {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileExtensions = config.fileUpload?.fileExtensions;
|
||||
if (!isMaster && fileExtensions) {
|
||||
const isValidExtension = extension => {
|
||||
return fileExtensions.some(ext => {
|
||||
if (ext === '*') {
|
||||
return true;
|
||||
}
|
||||
const regex = new RegExp(fileExtensions);
|
||||
if (regex.test(extension)) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
let extension = contentType;
|
||||
if (filename && filename.includes('.')) {
|
||||
extension = filename.split('.')[1];
|
||||
} else if (contentType && contentType.includes('/')) {
|
||||
extension = contentType.split('/')[1];
|
||||
}
|
||||
extension = extension.split(' ').join('');
|
||||
|
||||
if (!isValidExtension(extension)) {
|
||||
next(
|
||||
new Parse.Error(
|
||||
Parse.Error.FILE_SAVE_ERROR,
|
||||
`File upload of extension ${extension} is disabled.`
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const base64 = req.body.toString('base64');
|
||||
const file = new Parse.File(filename, { base64 }, contentType);
|
||||
const { metadata = {}, tags = {} } = req.fileData || {};
|
||||
|
||||
Reference in New Issue
Block a user