fix: force download of unsafe extensions
This commit is contained in:
parent
57b56d3a5b
commit
79bdd44093
@ -151,6 +151,15 @@
|
|||||||
persistent-hint
|
persistent-hint
|
||||||
hint='Should SVG uploads be scanned for vulnerabilities and stripped of any potentially unsafe content.'
|
hint='Should SVG uploads be scanned for vulnerabilities and stripped of any potentially unsafe content.'
|
||||||
)
|
)
|
||||||
|
v-divider.mt-3
|
||||||
|
v-switch(
|
||||||
|
inset
|
||||||
|
label='Force Download of Unsafe Extensions'
|
||||||
|
color='primary'
|
||||||
|
v-model='config.uploadForceDownload'
|
||||||
|
persistent-hint
|
||||||
|
hint='Should non-image files be forced as downloads when accessed directly. This prevents potential XSS attacks via unsafe file extensions uploads.'
|
||||||
|
)
|
||||||
|
|
||||||
v-card.mt-3.animated.fadeInUp.wait-p2s
|
v-card.mt-3.animated.fadeInUp.wait-p2s
|
||||||
v-toolbar(flat, color='primary', dark, dense)
|
v-toolbar(flat, color='primary', dark, dense)
|
||||||
@ -252,6 +261,7 @@ export default {
|
|||||||
uploadMaxFileSize: 0,
|
uploadMaxFileSize: 0,
|
||||||
uploadMaxFiles: 0,
|
uploadMaxFiles: 0,
|
||||||
uploadScanSVG: true,
|
uploadScanSVG: true,
|
||||||
|
uploadForceDownload: true,
|
||||||
securityOpenRedirect: true,
|
securityOpenRedirect: true,
|
||||||
securityIframe: true,
|
securityIframe: true,
|
||||||
securityReferrerPolicy: true,
|
securityReferrerPolicy: true,
|
||||||
@ -297,6 +307,7 @@ export default {
|
|||||||
$uploadMaxFileSize: Int
|
$uploadMaxFileSize: Int
|
||||||
$uploadMaxFiles: Int
|
$uploadMaxFiles: Int
|
||||||
$uploadScanSVG: Boolean
|
$uploadScanSVG: Boolean
|
||||||
|
$uploadForceDownload: Boolean
|
||||||
$securityOpenRedirect: Boolean
|
$securityOpenRedirect: Boolean
|
||||||
$securityIframe: Boolean
|
$securityIframe: Boolean
|
||||||
$securityReferrerPolicy: Boolean
|
$securityReferrerPolicy: Boolean
|
||||||
@ -319,6 +330,7 @@ export default {
|
|||||||
uploadMaxFileSize: $uploadMaxFileSize,
|
uploadMaxFileSize: $uploadMaxFileSize,
|
||||||
uploadMaxFiles: $uploadMaxFiles,
|
uploadMaxFiles: $uploadMaxFiles,
|
||||||
uploadScanSVG: $uploadScanSVG
|
uploadScanSVG: $uploadScanSVG
|
||||||
|
uploadForceDownload: $uploadForceDownload,
|
||||||
securityOpenRedirect: $securityOpenRedirect,
|
securityOpenRedirect: $securityOpenRedirect,
|
||||||
securityIframe: $securityIframe,
|
securityIframe: $securityIframe,
|
||||||
securityReferrerPolicy: $securityReferrerPolicy,
|
securityReferrerPolicy: $securityReferrerPolicy,
|
||||||
@ -350,6 +362,7 @@ export default {
|
|||||||
uploadMaxFileSize: _.toSafeInteger(_.get(this.config, 'uploadMaxFileSize', 0)),
|
uploadMaxFileSize: _.toSafeInteger(_.get(this.config, 'uploadMaxFileSize', 0)),
|
||||||
uploadMaxFiles: _.toSafeInteger(_.get(this.config, 'uploadMaxFiles', 0)),
|
uploadMaxFiles: _.toSafeInteger(_.get(this.config, 'uploadMaxFiles', 0)),
|
||||||
uploadScanSVG: _.get(this.config, 'uploadScanSVG', false),
|
uploadScanSVG: _.get(this.config, 'uploadScanSVG', false),
|
||||||
|
uploadForceDownload: _.get(this.config, 'uploadForceDownload', false),
|
||||||
securityOpenRedirect: _.get(this.config, 'securityOpenRedirect', false),
|
securityOpenRedirect: _.get(this.config, 'securityOpenRedirect', false),
|
||||||
securityIframe: _.get(this.config, 'securityIframe', false),
|
securityIframe: _.get(this.config, 'securityIframe', false),
|
||||||
securityReferrerPolicy: _.get(this.config, 'securityReferrerPolicy', false),
|
securityReferrerPolicy: _.get(this.config, 'securityReferrerPolicy', false),
|
||||||
@ -402,6 +415,7 @@ export default {
|
|||||||
uploadMaxFileSize
|
uploadMaxFileSize
|
||||||
uploadMaxFiles
|
uploadMaxFiles
|
||||||
uploadScanSVG
|
uploadScanSVG
|
||||||
|
uploadForceDownload
|
||||||
securityOpenRedirect
|
securityOpenRedirect
|
||||||
securityIframe
|
securityIframe
|
||||||
securityReferrerPolicy
|
securityReferrerPolicy
|
||||||
|
@ -81,6 +81,7 @@ defaults:
|
|||||||
maxFileSize: 5242880
|
maxFileSize: 5242880
|
||||||
maxFiles: 10
|
maxFiles: 10
|
||||||
scanSVG: true
|
scanSVG: true
|
||||||
|
forceDownload: true
|
||||||
flags:
|
flags:
|
||||||
ldapdebug: false
|
ldapdebug: false
|
||||||
sqllog: false
|
sqllog: false
|
||||||
|
@ -30,7 +30,8 @@ module.exports = {
|
|||||||
authJwtRenewablePeriod: WIKI.config.auth.tokenRenewal,
|
authJwtRenewablePeriod: WIKI.config.auth.tokenRenewal,
|
||||||
uploadMaxFileSize: WIKI.config.uploads.maxFileSize,
|
uploadMaxFileSize: WIKI.config.uploads.maxFileSize,
|
||||||
uploadMaxFiles: WIKI.config.uploads.maxFiles,
|
uploadMaxFiles: WIKI.config.uploads.maxFiles,
|
||||||
uploadScanSVG: WIKI.config.uploads.scanSVG
|
uploadScanSVG: WIKI.config.uploads.scanSVG,
|
||||||
|
uploadForceDownload: WIKI.config.uploads.forceDownload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -99,7 +100,8 @@ module.exports = {
|
|||||||
WIKI.config.uploads = {
|
WIKI.config.uploads = {
|
||||||
maxFileSize: _.get(args, 'uploadMaxFileSize', WIKI.config.uploads.maxFileSize),
|
maxFileSize: _.get(args, 'uploadMaxFileSize', WIKI.config.uploads.maxFileSize),
|
||||||
maxFiles: _.get(args, 'uploadMaxFiles', WIKI.config.uploads.maxFiles),
|
maxFiles: _.get(args, 'uploadMaxFiles', WIKI.config.uploads.maxFiles),
|
||||||
scanSVG: _.get(args, 'uploadScanSVG', WIKI.config.uploads.scanSVG)
|
scanSVG: _.get(args, 'uploadScanSVG', WIKI.config.uploads.scanSVG),
|
||||||
|
forceDownload: _.get(args, 'uploadForceDownload', WIKI.config.uploads.forceDownload)
|
||||||
}
|
}
|
||||||
|
|
||||||
await WIKI.configSvc.saveToDb(['host', 'title', 'company', 'contentLicense', 'seo', 'logoUrl', 'auth', 'features', 'security', 'uploads'])
|
await WIKI.configSvc.saveToDb(['host', 'title', 'company', 'contentLicense', 'seo', 'logoUrl', 'auth', 'features', 'security', 'uploads'])
|
||||||
|
@ -55,6 +55,7 @@ type SiteMutation {
|
|||||||
uploadMaxFileSize: Int
|
uploadMaxFileSize: Int
|
||||||
uploadMaxFiles: Int
|
uploadMaxFiles: Int
|
||||||
uploadScanSVG: Boolean
|
uploadScanSVG: Boolean
|
||||||
|
uploadForceDownload: Boolean
|
||||||
|
|
||||||
): DefaultResponse @auth(requires: ["manage:system"])
|
): DefaultResponse @auth(requires: ["manage:system"])
|
||||||
}
|
}
|
||||||
@ -95,4 +96,5 @@ type SiteConfig {
|
|||||||
uploadMaxFileSize: Int
|
uploadMaxFileSize: Int
|
||||||
uploadMaxFiles: Int
|
uploadMaxFiles: Int
|
||||||
uploadScanSVG: Boolean
|
uploadScanSVG: Boolean
|
||||||
|
uploadForceDownload: Boolean
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
@ -6,5 +7,9 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
generateHash(assetPath) {
|
generateHash(assetPath) {
|
||||||
return crypto.createHash('sha1').update(assetPath).digest('hex')
|
return crypto.createHash('sha1').update(assetPath).digest('hex')
|
||||||
|
},
|
||||||
|
|
||||||
|
getPathInfo(assetPath) {
|
||||||
|
return path.parse(assetPath.toLowerCase())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,8 +168,15 @@ module.exports = class Asset extends Model {
|
|||||||
|
|
||||||
static async getAsset(assetPath, res) {
|
static async getAsset(assetPath, res) {
|
||||||
try {
|
try {
|
||||||
|
const fileInfo = assetHelper.getPathInfo(assetPath)
|
||||||
const fileHash = assetHelper.generateHash(assetPath)
|
const fileHash = assetHelper.generateHash(assetPath)
|
||||||
const cachePath = path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, `cache/${fileHash}.dat`)
|
const cachePath = path.resolve(WIKI.ROOTPATH, WIKI.config.dataPath, `cache/${fileHash}.dat`)
|
||||||
|
|
||||||
|
// Force unsafe extensions to download
|
||||||
|
if (WIKI.config.uploads.forceDownload && !['.png', '.apng', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.svg'].includes(fileInfo.ext)) {
|
||||||
|
res.set('Content-disposition', 'attachment; filename=' + fileInfo.base)
|
||||||
|
}
|
||||||
|
|
||||||
if (await WIKI.models.assets.getAssetFromCache(assetPath, cachePath, res)) {
|
if (await WIKI.models.assets.getAssetFromCache(assetPath, cachePath, res)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user