diff --git a/src/nginxconfig/generators/conf/security.conf.js b/src/nginxconfig/generators/conf/security.conf.js index 4335c36..b87f223 100644 --- a/src/nginxconfig/generators/conf/security.conf.js +++ b/src/nginxconfig/generators/conf/security.conf.js @@ -32,37 +32,235 @@ export default (domains, global) => { config.push(['# security headers', '']); config.push(['add_header X-XSS-Protection', '"1; mode=block" always']); config.push(['add_header X-Content-Type-Options', '"nosniff" always']); - config.push(['add_header Referrer-Policy', `"${global.security.referrerPolicy.computed}" always`]); + config.push([ + 'add_header Referrer-Policy', + `"${global.security.referrerPolicy.computed}" always`, + ]); if (global.security.contentSecurityPolicy.computed) - config.push(['add_header Content-Security-Policy', `"${global.security.contentSecurityPolicy.computed}" always`]); + config.push([ + 'add_header Content-Security-Policy', + `"${global.security.contentSecurityPolicy.computed}" always`, + ]); if (global.security.permissionsPolicy.computed) - config.push(['add_header Permissions-Policy', `"${global.security.permissionsPolicy.computed}" always`]); + config.push([ + 'add_header Permissions-Policy', + `"${global.security.permissionsPolicy.computed}" always`, + ]); // Every domain has HSTS enabled, and they all have same hstsSubdomains/hstsPreload settings if (commonHsts(domains)) { - const commonHSTSSubdomains = domains.length && domains[0].https.hstsSubdomains.computed; - const commonHSTSPreload = domains.length && domains[0].https.hstsPreload.computed; - config.push(['add_header Strict-Transport-Security', `"max-age=31536000${commonHSTSSubdomains ? '; includeSubDomains' : ''}${commonHSTSPreload ? '; preload' : ''}" always`]); + const commonHSTSSubdomains = + domains.length && domains[0].https.hstsSubdomains.computed; + const commonHSTSPreload = + domains.length && domains[0].https.hstsPreload.computed; + config.push([ + 'add_header Strict-Transport-Security', + `"max-age=31536000${ + commonHSTSSubdomains ? '; includeSubDomains' : '' + }${commonHSTSPreload ? '; preload' : ''}" always`, + ]); } config.push(['# . files', '']); - config.push(['location ~ /\\.(?!well-known)', { - deny: 'all', - }]); + config.push([ + 'location ~ /\\.(?!well-known)', + { + deny: 'all', + }, + ]); // Security.txt if (global.security.securityTxt.computed) { config.push(['# security.txt', '']); - config.push(['location /security.txt', { - return: '301 /.well-known/security.txt', - }]); - + config.push([ + 'location /security.txt', + { + return: '301 /.well-known/security.txt', + }, + ]); + // Custom security.txt path - config.push(['location = /.well-known/security.txt', { - alias: `${global.security.securityTxtPath.value}`, - }]); + config.push([ + 'location = /.well-known/security.txt', + { + alias: `${global.security.securityTxtPath.value}`, + }, + ]); + } + + if (global.security.blockCommonExploits.computed) { + // Block SQL Injections + config.push(['## Block SQL injections', '']); + config.push(['set $block_sql_injections', '0']); + config.push([ + 'if ($query_string ~ "union.*select.*(")', + { + set: '$block_sql_injections 1', + }, + ]); + config.push([ + 'if ($query_string ~ "union.*all.*select.*")', + { + set: '$block_sql_injections 1', + }, + ]); + config.push([ + 'if ($query_string ~ "concat.*(")', + { + set: '$block_sql_injections 1', + }, + ]); + config.push(['if ($block_sql_injections = 1)', { return: '403' }]); + + // Block file injections + config.push(['## Block file injections', '']); + config.push(['set $block_file_injections', '0']); + config.push([ + 'if ($query_string ~ "[a-zA-Z0-9_]=http://")', + { set: '$block_file_injections 1' }, + ]); + config.push([ + 'if ($query_string ~ "[a-zA-Z0-9_]=(..//?)+")', // eslint-disable-line + { set: '$block_file_injections 1' }, + ]); + config.push([ + 'if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+")', // eslint-disable-line + { set: '$block_file_injections 1' }, + ]); + config.push(['if ($block_file_injections = 1)', { return: '403' }]); + + // Block common exploits + config.push(['## Block common exploits', '']); + config.push(['set $block_common_exploits', '0']); + config.push([ + 'if ($query_string ~ "(<|%3C).*script.*(>|%3E)")', + { + set: '$block_common_exploits 1', + }, + ]); + config.push([ + 'if ($query_string ~ "GLOBALS(=|[|%[0-9A-Z]{0,2})")', + { + set: '$block_common_exploits 1', + }, + ]); + config.push([ + 'if ($query_string ~ "_REQUEST(=|[|%[0-9A-Z]{0,2})")', + { + set: '$block_common_exploits 1', + }, + ]); + config.push([ + 'if ($query_string ~ "proc/self/environ")', + { + set: '$block_common_exploits 1', + }, + ]); + config.push([ + 'if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|%3D)")', + { + set: '$block_common_exploits 1', + }, + ]); + config.push([ + 'if ($query_string ~ "base64_(en|de)code(.*)")', + { + set: '$block_common_exploits 1', + }, + ]); + config.push(['if ($block_common_exploits = 1)', { return: '403' }]); + + // Block spam + config.push(['# Block spam', '']); + config.push(['set $block_spam', '0']); + config.push([ + 'if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b")', // eslint-disable-line + { + set: '$block_spam 1', + }, + ]); + config.push([ + 'if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b")', // eslint-disable-line + { + set: '$block_spam 1', + }, + ]); + config.push([ + 'if ($query_string ~ "\b(ambien|bluespill|cialis|cocaine|ejaculation|erectile)\b")', // eslint-disable-line + { + set: '$block_spam 1', + }, + ]); + config.push([ + 'if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b")', // eslint-disable-line + { + set: '$block_spam 1', + }, + ]); + config.push(['if ($block_spam = 1)', { return: '403' }]); + + // Block user agents + config.push(['$Block user agents', '']); + config.push(['set $block_user_agents', '0']); + config.push(['# Disable Akeeba Remote Control 2.5 and earlier', '']); + config.push([ + 'if ($http_user_agent ~ "Indy Library")', + { + set: '$block_user_agents 1', + }, + ]); + config.push(['# Common bandwidth hoggers and hacking tools.', '']); + config.push([ + 'if ($http_user_agent ~ "libwww-perl")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "GetRight")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "GetWeb!")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "Go!Zilla")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "Download Demon")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "Go-Ahead-Got-It")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "TurnitinBot")', + { + set: '$block_user_agents 1', + }, + ]); + config.push([ + 'if ($http_user_agent ~ "GrabNet")', + { + set: '$block_user_agents 1', + }, + ]); + config.push(['if ($block_user_agents = 1)', { return: '403' }]); } // Done! diff --git a/src/nginxconfig/templates/global_sections/security.vue b/src/nginxconfig/templates/global_sections/security.vue index 694b222..6451b48 100644 --- a/src/nginxconfig/templates/global_sections/security.vue +++ b/src/nginxconfig/templates/global_sections/security.vue @@ -32,7 +32,13 @@ THE SOFTWARE.
-
+
-
+
-
+
-
+
@@ -75,7 +104,13 @@ THE SOFTWARE.
-
+
-
+
- - {{ $t('common.enable') }} + + {{ $t("common.enable") }}
@@ -110,10 +152,17 @@ THE SOFTWARE.
-
+
- - {{ $t('common.enable') }} + + {{ $t("common.enable") }}
@@ -129,8 +178,11 @@ THE SOFTWARE.
- - {{ $t('common.enable') }} + + {{ $t("common.enable") }}
@@ -138,13 +190,20 @@ THE SOFTWARE.
-
+
-
+
+ +
+
+ +
+
+
+
+
+ + {{ $t("common.enable") }} + +
+
+
+
+
@@ -180,7 +263,8 @@ THE SOFTWARE. enabled: true, }, contentSecurityPolicy: { - default: 'default-src \'self\' http: https: ws: wss: data: blob: \'unsafe-inline\'; frame-ancestors \'self\';', + default: + 'default-src \'self\' http: https: ws: wss: data: blob: \'unsafe-inline\'; frame-ancestors \'self\';', enabled: true, }, permissionsPolicy: { @@ -203,28 +287,37 @@ THE SOFTWARE. default: '~/security.txt', enabled: true, }, + blockCommonExploits: { + default: false, + enabled: true, + }, }; export default { - name: 'GlobalSecurity', // Component name - display: 'templates.globalSections.security.security', // Display name for tab (i18n key) - key: 'security', // Key for data in parent - delegated: delegatedFromDefaults(defaults), // Data the parent will present here + name: 'GlobalSecurity', // Component name + display: 'templates.globalSections.security.security', // Display name for tab (i18n key) + key: 'security', // Key for data in parent + delegated: delegatedFromDefaults(defaults), // Data the parent will present here components: { PrettyCheck, VueSelect, }, props: { - data: Object, // Data delegated back to us from parent + data: Object, // Data delegated back to us from parent }, computed: { - ...computedFromDefaults(defaults, 'security'), // Getters & setters for the delegated data + ...computedFromDefaults(defaults, 'security'), // Getters & setters for the delegated data hasWordPress() { - return this.$parent.$parent.$data.domains.some(d => d && d.php.wordPressRules.computed); + return this.$parent.$parent.$data.domains.some( + d => d && d.php.wordPressRules.computed, + ); }, hasWordPressUnsafeEval() { - return this.$props.data.contentSecurityPolicy.computed - .match(/(default|script)-src[^;]+'self'[^;]+'unsafe-inline'[^;]+'unsafe-eval'[^;]*;/) !== null; + return ( + this.$props.data.contentSecurityPolicy.computed.match( + /(default|script)-src[^;]+'self'[^;]+'unsafe-inline'[^;]+'unsafe-eval'[^;]*;/, + ) !== null + ); }, hasWarnings() { return this.hasWordPress && !this.hasWordPressUnsafeEval;