feat: Block common exploits in Security
This commit is contained in:
parent
e95e615c18
commit
5c1e422d7d
|
@ -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!
|
||||
|
|
|
@ -32,7 +32,13 @@ THE SOFTWARE.
|
|||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div :class="`control${referrerPolicyChanged ? ' is-changed' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`control${
|
||||
referrerPolicyChanged ? ' is-changed' : ''
|
||||
}`
|
||||
"
|
||||
>
|
||||
<VueSelect
|
||||
v-model="referrerPolicy"
|
||||
:options="$props.data.referrerPolicy.options"
|
||||
|
@ -43,25 +49,48 @@ THE SOFTWARE.
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="`field is-horizontal${hasWordPress && !hasUnsafeEval ? ' is-aligned-top' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`field is-horizontal${
|
||||
hasWordPress && !hasUnsafeEval ? ' is-aligned-top' : ''
|
||||
}`
|
||||
"
|
||||
>
|
||||
<div class="field-label">
|
||||
<label class="label">Content-Security-Policy</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div :class="`control${contentSecurityPolicyChanged ? ' is-changed' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`control${
|
||||
contentSecurityPolicyChanged
|
||||
? ' is-changed'
|
||||
: ''
|
||||
}`
|
||||
"
|
||||
>
|
||||
<input
|
||||
v-model="contentSecurityPolicy"
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="$props.data.contentSecurityPolicy.default"
|
||||
:placeholder="
|
||||
$props.data.contentSecurityPolicy.default
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="hasWordPress && !hasWordPressUnsafeEval" class="control">
|
||||
<div
|
||||
v-if="hasWordPress && !hasWordPressUnsafeEval"
|
||||
class="control"
|
||||
>
|
||||
<label class="text message is-warning">
|
||||
<span
|
||||
class="message-body"
|
||||
v-html="$t('templates.globalSections.security.whenUsingWordPressUnsafeEvalIsOftenRequiredToAllowFunctionality')"
|
||||
v-html="
|
||||
$t(
|
||||
'templates.globalSections.security.whenUsingWordPressUnsafeEvalIsOftenRequiredToAllowFunctionality'
|
||||
)
|
||||
"
|
||||
></span>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -75,7 +104,13 @@ THE SOFTWARE.
|
|||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div :class="`control${permissionsPolicyChanged ? ' is-changed' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`control${
|
||||
permissionsPolicyChanged ? ' is-changed' : ''
|
||||
}`
|
||||
"
|
||||
>
|
||||
<input
|
||||
v-model="permissionsPolicy"
|
||||
class="input"
|
||||
|
@ -93,10 +128,17 @@ THE SOFTWARE.
|
|||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div :class="`control${serverTokensChanged ? ' is-changed' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`control${serverTokensChanged ? ' is-changed' : ''}`
|
||||
"
|
||||
>
|
||||
<div class="checkbox">
|
||||
<PrettyCheck v-model="serverTokens" class="p-default p-curve p-fill p-icon">
|
||||
{{ $t('common.enable') }}
|
||||
<PrettyCheck
|
||||
v-model="serverTokens"
|
||||
class="p-default p-curve p-fill p-icon"
|
||||
>
|
||||
{{ $t("common.enable") }}
|
||||
</PrettyCheck>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -110,10 +152,17 @@ THE SOFTWARE.
|
|||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div :class="`control${limitReqChanged ? ' is-changed' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`control${limitReqChanged ? ' is-changed' : ''}`
|
||||
"
|
||||
>
|
||||
<div class="checkbox">
|
||||
<PrettyCheck v-model="limitReq" class="p-default p-curve p-fill p-icon">
|
||||
{{ $t('common.enable') }}
|
||||
<PrettyCheck
|
||||
v-model="limitReq"
|
||||
class="p-default p-curve p-fill p-icon"
|
||||
>
|
||||
{{ $t("common.enable") }}
|
||||
</PrettyCheck>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -129,8 +178,11 @@ THE SOFTWARE.
|
|||
<div class="field">
|
||||
<div :class="`control${securityTxt ? ' is-changed' : ''}`">
|
||||
<div class="checkbox">
|
||||
<PrettyCheck v-model="securityTxt" class="p-default p-curve p-fill p-icon">
|
||||
{{ $t('common.enable') }}
|
||||
<PrettyCheck
|
||||
v-model="securityTxt"
|
||||
class="p-default p-curve p-fill p-icon"
|
||||
>
|
||||
{{ $t("common.enable") }}
|
||||
</PrettyCheck>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -138,13 +190,20 @@ THE SOFTWARE.
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="$props.data.securityTxt.computed" class="field is-horizontal">
|
||||
<div
|
||||
v-if="$props.data.securityTxt.computed"
|
||||
class="field is-horizontal"
|
||||
>
|
||||
<div class="field-label">
|
||||
<label class="label">security.txt path</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div :class="`control${securityTxtChanged ? ' is-changed' : ''}`">
|
||||
<div
|
||||
:class="
|
||||
`control${securityTxtChanged ? ' is-changed' : ''}`
|
||||
"
|
||||
>
|
||||
<input
|
||||
v-model="securityTxtPath"
|
||||
class="input"
|
||||
|
@ -155,6 +214,30 @@ THE SOFTWARE.
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">Block common exploits</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div
|
||||
:class="
|
||||
`control${blockCommonExploits ? ' is-changed' : ''}`
|
||||
"
|
||||
>
|
||||
<div class="checkbox">
|
||||
<PrettyCheck
|
||||
v-model="blockCommonExploits"
|
||||
class="p-default p-curve p-fill p-icon"
|
||||
>
|
||||
{{ $t("common.enable") }}
|
||||
</PrettyCheck>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue