From 412d1a9851018f161a2e124e3fa9f2033fc9f3fe Mon Sep 17 00:00:00 2001 From: Izorkin Date: Sun, 19 Dec 2021 17:07:17 +0200 Subject: [PATCH] enable modsecurity to nextcloud --- configuration.nix | 1 + .../webserver/modsecurity/default.nix | 74 +++++++++++++++++++ generic/services/webserver/nginx.nix | 4 + 3 files changed, 79 insertions(+) create mode 100644 generic/services/webserver/modsecurity/default.nix diff --git a/configuration.nix b/configuration.nix index 05242d7..068cf5d 100644 --- a/configuration.nix +++ b/configuration.nix @@ -21,6 +21,7 @@ in ./generic/services/social/pleroma.nix ./generic/services/videomeet/jitsi.nix ./generic/services/vpn/ocserv.nix + ./generic/services/webserver/modsecurity/default.nix ./generic/services/webserver/memcached.nix ./generic/services/webserver/nginx.nix ./generic/system/limits.nix diff --git a/generic/services/webserver/modsecurity/default.nix b/generic/services/webserver/modsecurity/default.nix new file mode 100644 index 0000000..8ce0a74 --- /dev/null +++ b/generic/services/webserver/modsecurity/default.nix @@ -0,0 +1,74 @@ +{config, pkgs, ... }: +{ + environment.etc."modsecurity/modsecurity_includes.conf".text = '' + Include /etc/modsecurity/modsecurity.conf + Include /etc/modsecurity/crs-setup.conf + Include ${pkgs.spdev.modsecurity-crs}/rules/*.conf + ''; + + environment.etc."modsecurity/modsecurity.conf".text = '' + SecRuleEngine On + SecRequestBodyAccess On + SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ + "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" + SecRule REQUEST_HEADERS:Content-Type "application/json" \ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRequestBodyLimit 13107200 + SecRequestBodyNoFilesLimit 131072 + SecRequestBodyLimitAction Reject + SecRule REQBODY_ERROR "!@eq 0" \ + "id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ + "id:'200003',phase:2,t:none,log,deny,status:400, \ + msg:'Multipart request body failed strict validation: \ + PE %{REQBODY_PROCESSOR_ERROR}, \ + BQ %{MULTIPART_BOUNDARY_QUOTED}, \ + BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ + DB %{MULTIPART_DATA_BEFORE}, \ + DA %{MULTIPART_DATA_AFTER}, \ + HF %{MULTIPART_HEADER_FOLDING}, \ + LF %{MULTIPART_LF_LINE}, \ + SM %{MULTIPART_MISSING_SEMICOLON}, \ + IQ %{MULTIPART_INVALID_QUOTING}, \ + IP %{MULTIPART_INVALID_PART}, \ + IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ + FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" + SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \ + "id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" + SecPcreMatchLimit 1000 + SecPcreMatchLimitRecursion 1000 + SecRule TX:/^MSC_/ "!@streq 0" \ + "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + SecResponseBodyAccess On + SecResponseBodyMimeType text/plain text/html text/xml + SecResponseBodyLimit 524288 + SecResponseBodyLimitAction ProcessPartial + SecTmpDir /tmp/ + SecDataDir /tmp/ + SecDebugLog /var/log/nginx/modsec_debug.log + SecDebugLogLevel 3 + SecAuditEngine RelevantOnly + SecAuditLogRelevantStatus "^(?:5|4(?!04))" + SecAuditLogParts ABIJDEFHZ + SecAuditLogType Serial + SecAuditLog /var/log/nginx/modsec_audit.log + SecAuditLogFormat Json + SecArgumentSeparator & + SecCookieFormat 0 + SecUnicodeMapFile ${pkgs.spdev.libmodsecurity}/share/modsecurity/unicode.mapping 20127 + SecStatusEngine On + ''; + + environment.etc."modsecurity/crs-setup.conf".text = '' + SecDefaultAction "phase:1,log,auditlog,pass" + SecDefaultAction "phase:2,log,auditlog,pass" + SecCollectionTimeout 600 + SecAction \ + "id:900990,\ + phase:1,\ + nolog,\ + pass,\ + t:none,\ + setvar:tx.crs_setup_version=332" + ''; +} diff --git a/generic/services/webserver/nginx.nix b/generic/services/webserver/nginx.nix index 6868063..f037d28 100644 --- a/generic/services/webserver/nginx.nix +++ b/generic/services/webserver/nginx.nix @@ -40,6 +40,10 @@ in sslCertificate = "/var/lib/acme/${domain}/fullchain.pem"; sslCertificateKey = "/var/lib/acme/${domain}/key.pem"; forceSSL = true; + extraConfig = '' + modsecurity on; + modsecurity_rules_file /etc/modsecurity/modsecurity_includes.conf; + ''; locations = { "/" = { proxyPass = "http://127.0.0.1:80/";