feat: Block common exploits in Security
parent
e95e615c18
commit
5c1e422d7d
|
@ -32,37 +32,235 @@ export default (domains, global) => {
|
||||||
config.push(['# security headers', '']);
|
config.push(['# security headers', '']);
|
||||||
config.push(['add_header X-XSS-Protection', '"1; mode=block" always']);
|
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 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)
|
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)
|
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
|
// Every domain has HSTS enabled, and they all have same hstsSubdomains/hstsPreload settings
|
||||||
if (commonHsts(domains)) {
|
if (commonHsts(domains)) {
|
||||||
const commonHSTSSubdomains = domains.length && domains[0].https.hstsSubdomains.computed;
|
const commonHSTSSubdomains =
|
||||||
const commonHSTSPreload = domains.length && domains[0].https.hstsPreload.computed;
|
domains.length && domains[0].https.hstsSubdomains.computed;
|
||||||
config.push(['add_header Strict-Transport-Security', `"max-age=31536000${commonHSTSSubdomains ? '; includeSubDomains' : ''}${commonHSTSPreload ? '; preload' : ''}" always`]);
|
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(['# . files', '']);
|
||||||
config.push(['location ~ /\\.(?!well-known)', {
|
config.push([
|
||||||
|
'location ~ /\\.(?!well-known)',
|
||||||
|
{
|
||||||
deny: 'all',
|
deny: 'all',
|
||||||
}]);
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
// Security.txt
|
// Security.txt
|
||||||
if (global.security.securityTxt.computed) {
|
if (global.security.securityTxt.computed) {
|
||||||
config.push(['# security.txt', '']);
|
config.push(['# security.txt', '']);
|
||||||
config.push(['location /security.txt', {
|
config.push([
|
||||||
|
'location /security.txt',
|
||||||
|
{
|
||||||
return: '301 /.well-known/security.txt',
|
return: '301 /.well-known/security.txt',
|
||||||
}]);
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
// Custom security.txt path
|
// Custom security.txt path
|
||||||
config.push(['location = /.well-known/security.txt', {
|
config.push([
|
||||||
|
'location = /.well-known/security.txt',
|
||||||
|
{
|
||||||
alias: `${global.security.securityTxtPath.value}`,
|
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!
|
// Done!
|
||||||
|
|
|
@ -32,7 +32,13 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${referrerPolicyChanged ? ' is-changed' : ''}`">
|
<div
|
||||||
|
:class="
|
||||||
|
`control${
|
||||||
|
referrerPolicyChanged ? ' is-changed' : ''
|
||||||
|
}`
|
||||||
|
"
|
||||||
|
>
|
||||||
<VueSelect
|
<VueSelect
|
||||||
v-model="referrerPolicy"
|
v-model="referrerPolicy"
|
||||||
:options="$props.data.referrerPolicy.options"
|
:options="$props.data.referrerPolicy.options"
|
||||||
|
@ -43,25 +49,48 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="field-label">
|
||||||
<label class="label">Content-Security-Policy</label>
|
<label class="label">Content-Security-Policy</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${contentSecurityPolicyChanged ? ' is-changed' : ''}`">
|
<div
|
||||||
|
:class="
|
||||||
|
`control${
|
||||||
|
contentSecurityPolicyChanged
|
||||||
|
? ' is-changed'
|
||||||
|
: ''
|
||||||
|
}`
|
||||||
|
"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
v-model="contentSecurityPolicy"
|
v-model="contentSecurityPolicy"
|
||||||
class="input"
|
class="input"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="$props.data.contentSecurityPolicy.default"
|
:placeholder="
|
||||||
|
$props.data.contentSecurityPolicy.default
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="hasWordPress && !hasWordPressUnsafeEval" class="control">
|
<div
|
||||||
|
v-if="hasWordPress && !hasWordPressUnsafeEval"
|
||||||
|
class="control"
|
||||||
|
>
|
||||||
<label class="text message is-warning">
|
<label class="text message is-warning">
|
||||||
<span
|
<span
|
||||||
class="message-body"
|
class="message-body"
|
||||||
v-html="$t('templates.globalSections.security.whenUsingWordPressUnsafeEvalIsOftenRequiredToAllowFunctionality')"
|
v-html="
|
||||||
|
$t(
|
||||||
|
'templates.globalSections.security.whenUsingWordPressUnsafeEvalIsOftenRequiredToAllowFunctionality'
|
||||||
|
)
|
||||||
|
"
|
||||||
></span>
|
></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -75,7 +104,13 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${permissionsPolicyChanged ? ' is-changed' : ''}`">
|
<div
|
||||||
|
:class="
|
||||||
|
`control${
|
||||||
|
permissionsPolicyChanged ? ' is-changed' : ''
|
||||||
|
}`
|
||||||
|
"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
v-model="permissionsPolicy"
|
v-model="permissionsPolicy"
|
||||||
class="input"
|
class="input"
|
||||||
|
@ -93,10 +128,17 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${serverTokensChanged ? ' is-changed' : ''}`">
|
<div
|
||||||
|
:class="
|
||||||
|
`control${serverTokensChanged ? ' is-changed' : ''}`
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<PrettyCheck v-model="serverTokens" class="p-default p-curve p-fill p-icon">
|
<PrettyCheck
|
||||||
{{ $t('common.enable') }}
|
v-model="serverTokens"
|
||||||
|
class="p-default p-curve p-fill p-icon"
|
||||||
|
>
|
||||||
|
{{ $t("common.enable") }}
|
||||||
</PrettyCheck>
|
</PrettyCheck>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,10 +152,17 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${limitReqChanged ? ' is-changed' : ''}`">
|
<div
|
||||||
|
:class="
|
||||||
|
`control${limitReqChanged ? ' is-changed' : ''}`
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<PrettyCheck v-model="limitReq" class="p-default p-curve p-fill p-icon">
|
<PrettyCheck
|
||||||
{{ $t('common.enable') }}
|
v-model="limitReq"
|
||||||
|
class="p-default p-curve p-fill p-icon"
|
||||||
|
>
|
||||||
|
{{ $t("common.enable") }}
|
||||||
</PrettyCheck>
|
</PrettyCheck>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -129,8 +178,11 @@ THE SOFTWARE.
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${securityTxt ? ' is-changed' : ''}`">
|
<div :class="`control${securityTxt ? ' is-changed' : ''}`">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<PrettyCheck v-model="securityTxt" class="p-default p-curve p-fill p-icon">
|
<PrettyCheck
|
||||||
{{ $t('common.enable') }}
|
v-model="securityTxt"
|
||||||
|
class="p-default p-curve p-fill p-icon"
|
||||||
|
>
|
||||||
|
{{ $t("common.enable") }}
|
||||||
</PrettyCheck>
|
</PrettyCheck>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -138,13 +190,20 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="field-label">
|
||||||
<label class="label">security.txt path</label>
|
<label class="label">security.txt path</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div :class="`control${securityTxtChanged ? ' is-changed' : ''}`">
|
<div
|
||||||
|
:class="
|
||||||
|
`control${securityTxtChanged ? ' is-changed' : ''}`
|
||||||
|
"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
v-model="securityTxtPath"
|
v-model="securityTxtPath"
|
||||||
class="input"
|
class="input"
|
||||||
|
@ -155,6 +214,30 @@ THE SOFTWARE.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -180,7 +263,8 @@ THE SOFTWARE.
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
contentSecurityPolicy: {
|
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,
|
enabled: true,
|
||||||
},
|
},
|
||||||
permissionsPolicy: {
|
permissionsPolicy: {
|
||||||
|
@ -203,6 +287,10 @@ THE SOFTWARE.
|
||||||
default: '~/security.txt',
|
default: '~/security.txt',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
|
blockCommonExploits: {
|
||||||
|
default: false,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -220,11 +308,16 @@ THE SOFTWARE.
|
||||||
computed: {
|
computed: {
|
||||||
...computedFromDefaults(defaults, 'security'), // Getters & setters for the delegated data
|
...computedFromDefaults(defaults, 'security'), // Getters & setters for the delegated data
|
||||||
hasWordPress() {
|
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() {
|
hasWordPressUnsafeEval() {
|
||||||
return this.$props.data.contentSecurityPolicy.computed
|
return (
|
||||||
.match(/(default|script)-src[^;]+'self'[^;]+'unsafe-inline'[^;]+'unsafe-eval'[^;]*;/) !== null;
|
this.$props.data.contentSecurityPolicy.computed.match(
|
||||||
|
/(default|script)-src[^;]+'self'[^;]+'unsafe-inline'[^;]+'unsafe-eval'[^;]*;/,
|
||||||
|
) !== null
|
||||||
|
);
|
||||||
},
|
},
|
||||||
hasWarnings() {
|
hasWarnings() {
|
||||||
return this.hasWordPress && !this.hasWordPressUnsafeEval;
|
return this.hasWordPress && !this.hasWordPressUnsafeEval;
|
||||||
|
|
Loading…
Reference in New Issue