diff --git a/src/apps.js b/src/apps.js index 14daa3af9..3746deba2 100644 --- a/src/apps.js +++ b/src/apps.js @@ -68,6 +68,7 @@ var addons = require('./addons.js'), split = require('split'), superagent = require('superagent'), taskmanager = require('./taskmanager.js'), + url = require('url'), util = require('util'), uuid = require('node-uuid'), validator = require('validator'); @@ -218,6 +219,20 @@ function validateMemoryLimit(manifest, memoryLimit) { return null; } +// https://tools.ietf.org/html/rfc7034 +function validateXFrameOptions(xFrameOptions) { + assert.strictEqual(typeof xFrameOptions, 'string'); + + if (xFrameOptions === 'DENY') return null; + if (xFrameOptions === 'SAMEORIGIN') return null; + + var parts = xFrameOptions.split(' '); + if (parts.length !== 2 || parts[0] !== 'ALLOW-FROM') return new AppsError(AppsError.BAD_FIELD, 'xFrameOptions must be "DENY", "SAMEORIGIN" or "ALLOW-FROM uri"' ); + + var uri = url.parse(parts[1]); + return (uri.protocol === 'http:' || uri.protocol === 'https:') ? null : new AppsError(AppsError.BAD_FIELD, 'xFrameOptions ALLOW-FROM uri must be a valid http[s] uri' ); +} + function getDuplicateErrorDetails(location, portBindings, error) { assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof portBindings, 'object'); @@ -396,7 +411,8 @@ function install(data, auditSource, callback) { cert = data.cert || null, key = data.key || null, memoryLimit = data.memoryLimit || 0, - altDomain = data.altDomain || null; + altDomain = data.altDomain || null, + xFrameOptions = data.xFrameOptions || 'SAMEORIGIN'; assert(data.appStoreId || data.manifest); // atleast one of them is required @@ -421,6 +437,9 @@ function install(data, auditSource, callback) { error = validateMemoryLimit(manifest, memoryLimit); if (error) return callback(error); + error = validateXFrameOptions(xFrameOptions); + if (error) return callback(error); + // memoryLimit might come in as 0 if not specified memoryLimit = memoryLimit || manifest.memoryLimit || constants.DEFAULT_MEMORY_LIMIT; @@ -451,7 +470,8 @@ function install(data, auditSource, callback) { var data = { accessRestriction: accessRestriction, memoryLimit: memoryLimit, - altDomain: altDomain + altDomain: altDomain, + xFrameOptions: xFrameOptions }; appdb.add(appId, appStoreId, manifest, location, portBindings, data, function (error) { diff --git a/src/nginx.js b/src/nginx.js index 1020a22e4..1a0d6a16a 100644 --- a/src/nginx.js +++ b/src/nginx.js @@ -75,7 +75,7 @@ function configureApp(app, certFilePath, keyFilePath, callback) { endpoint: endpoint, certFilePath: certFilePath, keyFilePath: keyFilePath, - xFrameOptions: 'SAMEORIGIN' + xFrameOptions: app.xFrameOptions || 'SAMEORIGIN' }; var nginxConf = ejs.render(NGINX_APPCONFIG_EJS, data);