openresty to nginx+modsec #27

Closed
DarkFeather wants to merge 4 commits from nginx-conversion into main
24 changed files with 1149 additions and 96 deletions
Showing only changes of commit 5fa67890c2 - Show all commits

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ roles/ShadowArch/files/mirrorlist
roles/Sharingan/files/monit/checks/availability roles/Sharingan/files/monit/checks/availability
roles/Foundation/files/custom/public/img/** roles/Foundation/files/custom/public/img/**
venv/** venv/**
wiki/**
**/pkg/** **/pkg/**
**/src/** **/src/**
**pkg.tar.zst **pkg.tar.zst

View File

@ -9,23 +9,23 @@ install: clean compile
for opt in ${optlist}; do cp -pr $$opt ${pkgdir}/opt/aninix/${pkgdirname}/${opt}; done for opt in ${optlist}; do cp -pr $$opt ${pkgdir}/opt/aninix/${pkgdirname}/${opt}; done
make checkperm make checkperm
test: compile
#python3 -m pytest
clean: clean:
git clean -fdX git clean -fdX
uninstall: uninstall:
rm -Rf ${pkgdir}/opt/aninix/${pkgdirname}/ rm -Rf ${pkgdir}/opt/aninix/${pkgdirname}/
test: compile
#python3 -m pytest
checkperm:
chown -R root: ${pkgdir}/opt/aninix/${pkgdirname}/
chmod 0755 ${pkgdir}/opt/aninix/${pkgdirname}/
chmod -R a+r ${pkgdir}/opt/aninix/${pkgdirname}/
diff: diff:
@echo Nothing to do. @echo Nothing to do.
for opt in ${optlist}; do diff -r ${pkgdir}/opt/aninix/${pkgdirname}/${opt} $$opt; done for opt in ${optlist}; do diff -r ${pkgdir}/opt/aninix/${pkgdirname}/${opt} $$opt; done
reverse: reverse:
for opt in ${optlist}; do rsync -avzlp ${pkgdir}/opt/aninix/${pkgdirname}/${opt}/ $$opt; done for opt in ${optlist}; do rsync -avzlp ${pkgdir}/opt/aninix/${pkgdirname}/${opt}/ $$opt; done
checkperm:
chown -R root: ${pkgdir}/opt/aninix/${pkgdirname}/
chmod 0755 ${pkgdir}/opt/aninix/${pkgdirname}/
chmod -R a+r ${pkgdir}/opt/aninix/${pkgdirname}/

View File

@ -1,6 +1,4 @@
This project will discover and provide inventory intelligence to Sora, Shadowfeed, Geth, and Sharingan. It is named after the fictional Star Wars Imperial Intelligence organization that oversaw the various divisions of Intelligence and orchestrated their operations. This project is our Infrastructure-as-Code solution, detailing the deployment & some repeatable operational tasks of the AniNIX.
*Note*: This project is in progress -- former Makefiles from [ConfigPackages](/AniNIX/ConfigPackages) are being upgraded into Ansible playbooks here.
# How to use # How to use
@ -14,7 +12,7 @@ Take a look at `examples/msn0.yml` as an example inventory -- make sure you popu
Once you have your vault and inventory, use [AniNIX/ShadowArch](/AniNIX/ShadowArch) with your hypervisor to provision the base image for your machines, or [Raspbian](https://www.raspberrypi.org/). Once you have your vault and inventory, use [AniNIX/ShadowArch](/AniNIX/ShadowArch) with your hypervisor to provision the base image for your machines, or [Raspbian](https://www.raspberrypi.org/).
Then, use the SSHkey playbook to copy your key and the deploy playbook to set things up. Then, use the SSH key playbook to copy your key and the deploy playbook to set things up.
``` ```
ansible-playbook -i your-inventory.yml playbooks/sshkey.yml ansible-playbook -i your-inventory.yml playbooks/sshkey.yml
ansible-playbook -i your-inventory.yml playbooks/deploy.yml ansible-playbook -i your-inventory.yml playbooks/deploy.yml
@ -26,7 +24,22 @@ We've also added two scripts in `./bin` to make your life easier:
Happy hacking! Happy hacking!
# Etymology
The [Ubiqtorate](https://starwars.fandom.com/wiki/Ubiqtorate/Legends) was a far-reaching security orchestration entity within Palpatine's Empire. It was mean to collect and act on intelligence to improve the security posture of the regime. We use this project similarly -- Ubiqtorate is the Infrastructure-as-Code behind the throne, making changes and ensuring services stay in line.
# Relevant Files and Software
This project is mostly built on [Ansible](https://docs.ansible.com/). You will need to understand inventories, playbooks, and vaults at the minimum.
# Available Clients
None -- this project is used to describe actions for other services to take.
# Equivalents or Competition
Similar tools include Puppet, chef, salty, Ansible Tower, Terraform, etc. We have chosen to go the raw Ansible route, so that we don't have to maintain the build infrastructure separately and to make our responses more agile.
# Exceptions # Exceptions
Some services, such as AniNIX/Sharingan and AniNIX/Geth, store their configuration in internal datastructures and databases such that we cannot easily export our build for others to use. We will document what we have done for each of these as best we can in the README.md files for others to replicate. Backups of these services into AniNIX/Aether are therefore dumps of these databases and not available to share. Some services, such as AniNIX/Sharingan and AniNIX/Geth, store their configuration in internal datastructures and databases such that we cannot easily export our build for others to use. We will document what we have done for each of these as best we can in the README.md files for others to replicate. Backups of these services into AniNIX/Aether are therefore dumps of these databases and not available to share.

View File

@ -448,7 +448,7 @@ PROVIDER_CONFIG = data/sessions
; Session cookie name ; Session cookie name
COOKIE_NAME = i_like_gitea COOKIE_NAME = i_like_gitea
; If you use session in https only, default is false ; If you use session in https only, default is false
COOKIE_SECURE = false COOKIE_SECURE = true
; Enable set cookie, default is true ; Enable set cookie, default is true
ENABLE_SET_COOKIE = true ENABLE_SET_COOKIE = true
; Session GC time interval in seconds, default is 86400 (1 day) ; Session GC time interval in seconds, default is 86400 (1 day)

View File

@ -2,10 +2,10 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name default_server; server_name default_server;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
location / { location / {
@ -31,7 +31,7 @@ server {
} }
location /whatismyip { location /whatismyip {
include ../conf.d/fastcgi.config; include conf.d/fastcgi.config;
root /usr/share/webapps/aninix/; root /usr/share/webapps/aninix/;
location ~* whatismyip { location ~* whatismyip {
try_files $uri /whatismyip.php; try_files $uri /whatismyip.php;
@ -49,9 +49,9 @@ server {
server { server {
listen 443 ssl http2; listen 443 ssl http2;
server_name foundation.aninix.net; server_name foundation.aninix.net;
include sec.conf; include conf/sec.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
include default.csp.conf; include conf/default.csp.conf;
location / { location / {
rewrite ^/(.*)$ https://aninix.net/$1 permanent; rewrite ^/(.*)$ https://aninix.net/$1 permanent;

View File

@ -2,8 +2,8 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name adhan.aninix.net; server_name adhan.aninix.net;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
location / location /
{ {

View File

@ -2,14 +2,14 @@ server {
listen 443 ssl; listen 443 ssl;
server_name cyberbrain.aninix.net; server_name cyberbrain.aninix.net;
include local.conf; include conf/local.conf;
root /usr/share/webapps/; root /usr/share/webapps/;
client_max_body_size 5m; client_max_body_size 5m;
client_body_timeout 60; client_body_timeout 60;
include ../conf.d/fastcgi7.config; include conf.d/fastcgi.config;
location /mediawiki-gb/ { location /mediawiki-gb/ {
try_files $uri $uri/ @rewrite; try_files $uri $uri/ @rewrite;
@ -43,6 +43,6 @@ server {
deny all; deny all;
} }
include letsencrypt.conf; include conf/letsencrypt.conf;
} }

View File

@ -8,10 +8,10 @@ server {
listen 443 ssl; listen 443 ssl;
server_name geth.aninix.net; server_name geth.aninix.net;
include sec.conf; include conf/sec.conf;
# include default.csp.conf; # include conf/default.csp.conf;
# include local.conf; # include conf/local.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
location / location /
{ {

View File

@ -3,8 +3,8 @@ server {
listen 444 ssl http2; listen 444 ssl http2;
server_name sharingan.aninix.net; server_name sharingan.aninix.net;
include sec.conf; include conf/sec.conf;
# include default.csp.conf; # include conf/default.csp.conf;
location / location /
{ {

View File

@ -2,9 +2,9 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name irc.aninix.net; server_name irc.aninix.net;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
location / location /
{ {

View File

@ -2,14 +2,14 @@ server {
listen 443 ssl; listen 443 ssl;
server_name lykos.aninix.net; server_name lykos.aninix.net;
# include local.conf; # include conf/local.conf;
root /usr/share/webapps/; root /usr/share/webapps/;
client_max_body_size 5m; client_max_body_size 5m;
client_body_timeout 60; client_body_timeout 60;
include ../conf.d/fastcgi.config; include conf.d/fastcgi.config;
location / { location / {
try_files $uri $uri/ @rewrite; try_files $uri $uri/ @rewrite;
@ -34,6 +34,6 @@ server {
deny all; deny all;
} }
include letsencrypt.conf; include conf/letsencrypt.conf;
} }

View File

@ -2,13 +2,12 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name maat.aninix.net; server_name maat.aninix.net;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
location / location /
{ {
try_files $uri /index.html
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-Server $host;

View File

@ -2,14 +2,14 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name password.aninix.net; server_name password.aninix.net;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
location / { location / {
root /usr/share/webapps/self-service-password/htdocs/; root /usr/share/webapps/self-service-password/htdocs/;
# https://ltb-project.org/documentation/self-service-password/1.3/config_nginx # https://ltb-project.org/documentation/self-service-password/1config_nginx
index index.php index.html index.htm; index index.php index.html index.htm;
# Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
@ -28,7 +28,7 @@ server {
#error_log /dev/stdout warn; #error_log /dev/stdout warn;
#access_log /dev/stdout info; #access_log /dev/stdout info;
include ../conf.d/fastcgi.config; include conf.d/fastcgi.config;
} }
# deny access to . files, for security # deny access to . files, for security

View File

@ -3,10 +3,10 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name sharingan.aninix.net; server_name sharingan.aninix.net;
include sec.conf; include conf/sec.conf;
# include default.csp.conf; # include conf/default.csp.conf;
include local.conf; include conf/local.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
location / location /

View File

@ -2,11 +2,11 @@ server {
listen 443 ssl; listen 443 ssl;
server_name singularity.aninix.net; server_name singularity.aninix.net;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
include ../conf.d/fastcgi.config; include conf.d/fastcgi.config;
root /usr/share/webapps/tt-rss/; root /usr/share/webapps/tt-rss/;

View File

@ -2,9 +2,9 @@ server {
listen 443 ssl; listen 443 ssl;
server_name travelpawscvt.com; server_name travelpawscvt.com;
#include local.conf; #include conf/local.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
include ../conf.d/fastcgi.config; include conf.d/fastcgi.config;
root /opt/travelpawscvt; root /opt/travelpawscvt;

View File

@ -2,8 +2,8 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name wolfpack.aninix.net; server_name wolfpack.aninix.net;
include sec.conf; include conf/sec.conf;
include default.csp.conf; include conf/default.csp.conf;
location / location /
{ {
@ -12,5 +12,5 @@ server {
autoindex_format html; autoindex_format html;
} }
include letsencrypt.conf; include conf/letsencrypt.conf;
} }

View File

@ -3,9 +3,9 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name yggdrasil.aninix.net; server_name yggdrasil.aninix.net;
include sec.conf; include conf/sec.conf;
include letsencrypt.conf; include conf/letsencrypt.conf;
# include default.csp.conf; # include conf/default.csp.conf;
location / location /
{ {

View File

@ -1 +1 @@
add_header "Content-Security-Policy" "default-src data: 'self' aninix.net foundation.aninix.net; script-src foundation.aninix.net www.gstatic.com www.google.com js.stripe.com unsafe-inline ssl.google-analytics.com 'self' aninix.net foundation.aninix.net data: 'unsafe-inline' 'unsafe-eval'; style-src foundation.aninix.net 'self' aninix.net foundation.aninix.net 'unsafe-inline' fonts.googleapis.com fonts.gstatic.com; img-src foundation.aninix.net 'self' aninix.net foundation.aninix.net upload.wikimedia.org commons.wikimedia.org creativecommons.org www.w3.org stripe.com ssl.google-analytics.com; font-src fonts.gstatic.com data: 'self' aninix.net foundation.aninix.net; connect-src ssl.google-analytics.com js.stripe.com mb3admin.com 'self' aninix.net foundation.aninix.net; media-src blob: 'self' aninix.net foundation.aninix.net ; child-src blob: 'self' js.stripe.com aninix.net foundation.aninix.net www.google.com; form-action 'self' aninix.net foundation.aninix.net; upgrade-insecure-requests;"; add_header "Content-Security-Policy" "default-src data: 'self' aninix.net foundation.aninix.net; script-src foundation.aninix.net www.gstatic.com www.google.com js.stripe.com unsafe-inline ssl.google-analytics.com 'self' aninix.net foundation.aninix.net data: 'unsafe-inline' 'unsafe-eval'; style-src foundation.aninix.net 'self' aninix.net foundation.aninix.net 'unsafe-inline' fonts.googleapis.com fonts.gstatic.com; img-src foundation.aninix.net 'self' aninix.net foundation.aninix.net upload.wikimedia.org commons.wikimedia.org creativecommons.org www.w3.org stripe.com ssl.google-analytics.com; font-src fonts.gstatic.com data: 'self' aninix.net foundation.aninix.net; connect-src ssl.google-analytics.com js.stripe.com mb3admin.com 'self' aninix.net foundation.aninix.net; media-src blob: 'self' aninix.net foundation.aninix.net ; child-src blob: 'self' js.stripe.com aninix.net foundation.aninix.net www.google.com; form-action 'self' aninix.net foundation.aninix.net; upgrade-insecure-requests; base-uri 'self'; frame-ancestors 'self';";

View File

@ -0,0 +1,8 @@
/var/log/modsec_audit.log {
missingok
notifempty
create 640 http http
sharedscripts
compress
endscript
}

968
roles/WebServer/files/modsec.conf Executable file
View File

@ -0,0 +1,968 @@
# -- Rule engine initialization ----------------------------------------------
# Enable ModSecurity, attaching it to every transaction. Use detection
# only to start with, because that minimises the chances of post-installation
# disruption.
#
SecRuleEngine DetectionOnly
# -- Request body handling ---------------------------------------------------
# Allow ModSecurity to access request bodies. If you don't, ModSecurity
# won't be able to see any POST parameters, which opens a large security
# hole for attackers to exploit.
#
SecRequestBodyAccess On
# Enable XML request body parser.
# Initiate XML Processor in case of xml content-type
#
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" \
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
# Enable JSON request body parser.
# Initiate JSON Processor in case of JSON content-type; change accordingly
# if your application does not use 'application/json'
#
SecRule REQUEST_HEADERS:Content-Type "^application/json" \
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
# Sample rule to enable JSON request body parser for more subtypes.
# Uncomment or adapt this rule if you want to engage the JSON
# Processor for "+json" subtypes
#
#SecRule REQUEST_HEADERS:Content-Type "^application/[a-z0-9.-]+[+]json" \
# "id:'200006',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
# Maximum request body size we will accept for buffering. If you support
# file uploads then the value given on the first line has to be as large
# as the largest file you are willing to accept. The second value refers
# to the size of data, with files excluded. You want to keep that value as
# low as practical.
#
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
# What to do if the request body size is above our configured limit.
# Keep in mind that this setting will automatically be set to ProcessPartial
# when SecRuleEngine is set to DetectionOnly mode in order to minimize
# disruptions when initially deploying ModSecurity.
#
SecRequestBodyLimitAction Reject
# Maximum parsing depth allowed for JSON objects. You want to keep this
# value as low as practical.
#
SecRequestBodyJsonDepthLimit 512
# Maximum number of args allowed per request. You want to keep this
# value as low as practical. The value should match that in rule 200007.
SecArgumentsLimit 1000
# If SecArgumentsLimit has been set, you probably want to reject any
# request body that has only been partly parsed. The value used in this
# rule should match what was used with SecArgumentsLimit
SecRule &ARGS "@ge 1000" \
"id:'200007', phase:2,t:none,log,deny,status:400,msg:'Failed to fully parse request body due to large argument count',severity:2"
# Verify that we've correctly processed the request body.
# As a rule of thumb, when failing to process a request body
# you should reject the request (when deployed in blocking mode)
# or log a high-severity alert (when deployed in detection-only mode).
#
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"
# By default be strict with what we accept in the multipart/form-data
# request body. If the rule below proves to be too strict for your
# environment consider changing it to detection-only. You are encouraged
# _not_ to remove it altogether.
#
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}'"
# Did we see anything that might be a boundary?
#
# Here is a short description about the ModSecurity Multipart parser: the
# parser returns with value 0, if all "boundary-like" line matches with
# the boundary string which given in MIME header. In any other cases it returns
# with different value, eg. 1 or 2.
#
# The RFC 1341 descript the multipart content-type and its syntax must contains
# only three mandatory lines (above the content):
# * Content-Type: multipart/mixed; boundary=BOUNDARY_STRING
# * --BOUNDARY_STRING
# * --BOUNDARY_STRING--
#
# First line indicates, that this is a multipart content, second shows that
# here starts a part of the multipart content, third shows the end of content.
#
# If there are any other lines, which starts with "--", then it should be
# another boundary id - or not.
#
# After 3.0.3, there are two kinds of types of boundary errors: strict and permissive.
#
# If multipart content contains the three necessary lines with correct order, but
# there are one or more lines with "--", then parser returns with value 2 (non-zero).
#
# If some of the necessary lines (usually the start or end) misses, or the order
# is wrong, then parser returns with value 1 (also a non-zero).
#
# You can choose, which one is what you need. The example below contains the
# 'strict' mode, which means if there are any lines with start of "--", then
# ModSecurity blocked the content. But the next, commented example contains
# the 'permissive' mode, then you check only if the necessary lines exists in
# correct order. Whit this, you can enable to upload PEM files (eg "----BEGIN.."),
# or other text files, which contains eg. HTTP headers.
#
# The difference is only the operator - in strict mode (first) the content blocked
# in case of any non-zero value. In permissive mode (second, commented) the
# content blocked only if the value is explicit 1. If it 0 or 2, the content will
# allowed.
#
#
# See #1747 and #1924 for further information on the possible values for
# MULTIPART_UNMATCHED_BOUNDARY.
#
SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
# PCRE Tuning
# We want to avoid a potential RegEx DoS condition
#
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
# Some internal errors will set flags in TX and we will need to look for these.
# All of these are prefixed with "MSC_". The following flags currently exist:
#
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
#
SecRule TX:/^MSC_/ "!@streq 0" \
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
# -- Response body handling --------------------------------------------------
# Allow ModSecurity to access response bodies.
# You should have this directive enabled in order to identify errors
# and data leakage issues.
#
# Do keep in mind that enabling this directive does increases both
# memory consumption and response latency.
#
SecResponseBodyAccess On
# Which response MIME types do you want to inspect? You should adjust the
# configuration below to catch documents but avoid static files
# (e.g., images and archives).
#
SecResponseBodyMimeType text/plain text/html text/xml
# Buffer response bodies of up to 512 KB in length.
SecResponseBodyLimit 524288
# What happens when we encounter a response body larger than the configured
# limit? By default, we process what we have and let the rest through.
# That's somewhat less secure, but does not break any legitimate pages.
#
SecResponseBodyLimitAction ProcessPartial
# -- Filesystem configuration ------------------------------------------------
# The location where ModSecurity stores temporary files (for example, when
# it needs to handle a file upload that is larger than the configured limit).
#
# This default setting is chosen due to all systems have /tmp available however,
# this is less than ideal. It is recommended that you specify a location that's private.
#
SecTmpDir /var/log/modsec/tmp
# The location where ModSecurity will keep its persistent data. This default setting
# is chosen due to all systems have /tmp available however, it
# too should be updated to a place that other users can't access.
#
SecDataDir /var/log/modsec/data/
# -- File uploads handling configuration -------------------------------------
# The location where ModSecurity stores intercepted uploaded files. This
# location must be private to ModSecurity. You don't want other users on
# the server to access the files, do you?
#
SecUploadDir /opt/modsecurity/var/upload/
# By default, only keep the files that were determined to be unusual
# in some way (by an external inspection script). For this to work you
# will also need at least one file inspection rule.
#
SecUploadKeepFiles Off
# Uploaded files are by default created with permissions that do not allow
# any other user to access them. You may need to relax that if you want to
# interface ModSecurity to an external program (e.g., an anti-virus).
#
SecUploadFileMode 0600
# -- Debug log configuration -------------------------------------------------
# The default debug log configuration is to duplicate the error, warning
# and notice messages from the error log.
#
SecDebugLog /var/log/modsec/debug.log
SecDebugLogLevel 3
# -- Audit log configuration -------------------------------------------------
# Log the transactions that are marked by a rule, as well as those that
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
# level response status codes).
#
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
# Log everything we know about a transaction.
SecAuditLogParts ABIJDEFHZ
# Use a single file for logging. This is much easier to look at, but
# assumes that you will use the audit log only ocassionally.
#
SecAuditLogType Serial
SecAuditLog /var/log/modsec_audit.log
# Specify the path for concurrent audit logging.
SecAuditLogStorageDir /var/log/modsec/audit
# -- Miscellaneous -----------------------------------------------------------
# Use the most commonly used application/x-www-form-urlencoded parameter
# separator. There's probably only one application somewhere that uses
# something else so don't expect to change this value.
#
SecArgumentSeparator &
# Settle on version 0 (zero) cookies, as that is what most applications
# use. Using an incorrect cookie version may open your installation to
# evasion attacks (against the rules that examine named cookies).
#
SecCookieFormat 0
# Specify your Unicode Code Point.
# This mapping is used by the t:urlDecodeUni transformation function
# to properly map encoded data to your language. Properly setting
# these directives helps to reduce false positives and negatives.
#
#SecUnicodeMapFile unicode.mapping 20127
# Improve the quality of ModSecurity by sharing information about your
# current ModSecurity version and dependencies versions.
# The following information will be shared: ModSecurity version,
# Web Server version, APR version, PCRE version, Lua version, Libxml2
# version, Anonymous unique id for host.
SecStatusEngine On
# ------------------------------------------------------------------------
# OWASP ModSecurity Core Rule Set ver.4.0.0-rc1
# Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved.
# Copyright (c) 2021-2022 Core Rule Set project. All rights reserved.
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENSE file for full details.
# ------------------------------------------------------------------------
#
# -- [[ Introduction ]] --------------------------------------------------------
#
# The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack
# detection rules that provide a base level of protection for any web
# application. They are written for the open source, cross-platform
# ModSecurity Web Application Firewall.
#
# See also:
# https://coreruleset.org/
# https://github.com/coreruleset/coreruleset
# https://owasp.org/www-project-modsecurity-core-rule-set/
#
#
# -- [[ System Requirements ]] -------------------------------------------------
#
# CRS requires ModSecurity version 2.8.0 or above.
# We recommend to always use the newest ModSecurity version.
#
# The configuration directives/settings in this file are used to control
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
# ModSecurity settings (modsecurity.conf) such as SecRuleEngine,
# SecRequestBodyAccess, SecAuditEngine, SecDebugLog, and XML processing.
#
# The CRS assumes that modsecurity.conf has been loaded. It is bundled with
# ModSecurity. If you don't have it, you can get it from:
# 2.x: https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v2/master/modsecurity.conf-recommended
# 3.x: https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
#
# The order of file inclusion in your webserver configuration should always be:
# 1. modsecurity.conf
# 2. crs-setup.conf (this file)
# 3. rules/*.conf (the CRS rule files)
#
# Please refer to the INSTALL file for detailed installation instructions.
#
#
# -- [[ Mode of Operation: Anomaly Scoring vs. Self-Contained ]] ---------------
#
# The CRS can run in two modes:
#
# -- [[ Anomaly Scoring Mode (default) ]] --
# In CRS3, anomaly mode is the default and recommended mode, since it gives the
# most accurate log information and offers the most flexibility in setting your
# blocking policies. It is also called "collaborative detection mode".
# In this mode, each matching rule increases an 'anomaly score'.
# At the conclusion of the inbound rules, and again at the conclusion of the
# outbound rules, the anomaly score is checked, and the blocking evaluation
# rules apply a disruptive action, by default returning an error 403.
#
# -- [[ Self-Contained Mode ]] --
# In this mode, rules apply an action instantly. This was the CRS2 default.
# It can lower resource usage, at the cost of less flexibility in blocking policy
# and less informative audit logs (only the first detected threat is logged).
# Rules inherit the disruptive action that you specify (i.e. deny, drop, etc).
# The first rule that matches will execute this action. In most cases this will
# cause evaluation to stop after the first rule has matched, similar to how many
# IDSs function.
#
# -- [[ Alert Logging Control ]] --
# In the mode configuration, you must also adjust the desired logging options.
# There are three common options for dealing with logging. By default CRS enables
# logging to the webserver error log (or Event viewer) plus detailed logging to
# the ModSecurity audit log (configured under SecAuditLog in modsecurity.conf).
#
# - To log to both error log and ModSecurity audit log file, use: "log,auditlog"
# - To log *only* to the ModSecurity audit log file, use: "nolog,auditlog"
# - To log *only* to the error log file, use: "log,noauditlog"
#
# Examples for the various modes follow.
# You must leave one of the following options enabled.
# Note that you must specify the same line for phase:1 and phase:2.
#
# Default: Anomaly Scoring mode, log to error log, log to ModSecurity audit log
# - By default, offending requests are blocked with an error 403 response.
# - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example
# and review section 'Changing the Disruptive Action for Anomaly Mode'.
# - In Apache, you can use ErrorDocument to show a friendly error page or
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
#
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
# Example: Anomaly Scoring mode, log only to ModSecurity audit log
# - By default, offending requests are blocked with an error 403 response.
# - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example
# and review section 'Changing the Disruptive Action for Anomaly Mode'.
# - In Apache, you can use ErrorDocument to show a friendly error page or
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
#
# SecDefaultAction "phase:1,nolog,auditlog,pass"
# SecDefaultAction "phase:2,nolog,auditlog,pass"
# Example: Self-contained mode, return error 403 on blocking
# - In this configuration the default disruptive action becomes 'deny'. After a
# rule triggers, it will stop processing the request and return an error 403.
# - You can also use a different error status, such as 404, 406, et cetera.
# - In Apache, you can use ErrorDocument to show a friendly error page or
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
#
# SecDefaultAction "phase:1,log,auditlog,deny,status:403"
# SecDefaultAction "phase:2,log,auditlog,deny,status:403"
# Example: Self-contained mode, redirect back to homepage on blocking
# - In this configuration the 'tag' action includes the Host header data in the
# log. This helps to identify which virtual host triggered the rule (if any).
# - Note that this might cause redirect loops in some situations; for example
# if a Cookie or User-Agent header is blocked, it will also be blocked when
# the client subsequently tries to access the homepage. You can also redirect
# to another custom URL.
# SecDefaultAction "phase:1,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
# SecDefaultAction "phase:2,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
#
# -- [[ Paranoia Level Initialization ]] ---------------------------------------
#
# The Paranoia Level (PL) setting allows you to choose the desired level
# of rule checks that will add to your anomaly scores.
#
# With each paranoia level increase, the CRS enables additional rules
# giving you a higher level of security. However, higher paranoia levels
# also increase the possibility of blocking some legitimate traffic due to
# false alarms (also named false positives or FPs). If you use higher
# paranoia levels, it is likely that you will need to add some exclusion
# rules for certain requests and applications receiving complex input.
#
# - A paranoia level of 1 is default. In this level, most core rules
# are enabled. PL1 is advised for beginners, installations
# covering many different sites and applications, and for setups
# with standard security requirements.
# At PL1 you should face FPs rarely. If you encounter FPs, please
# open an issue on the CRS GitHub site and don't forget to attach your
# complete Audit Log record for the request with the issue.
# - Paranoia level 2 includes many extra rules, for instance enabling
# many regexp-based SQL and XSS injection protections, and adding
# extra keywords checked for code injections. PL2 is advised
# for moderate to experienced users desiring more complete coverage
# and for installations with elevated security requirements.
# PL2 comes with some FPs which you need to handle.
# - Paranoia level 3 enables more rules and keyword lists, and tweaks
# limits on special characters used. PL3 is aimed at users experienced
# at the handling of FPs and at installations with a high security
# requirement.
# - Paranoia level 4 further restricts special characters.
# The highest level is advised for experienced users protecting
# installations with very high security requirements. Running PL4 will
# likely produce a very high number of FPs which have to be
# treated before the site can go productive.
#
# All rules will log their PL to the audit log;
# example: [tag "paranoia-level/2"]. This allows you to deduct from the
# audit log how the WAF behavior is affected by paranoia level.
#
# It is important to also look into the variable
# tx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED)
# defined below. Enabling it closes a possible bypass of CRS.
#
# Uncomment this rule to change the default:
#
#SecAction \
# "id:900000,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.blocking_paranoia_level=1"
# It is possible to execute rules from a higher paranoia level but not include
# them in the anomaly scoring. This allows you to take a well-tuned system on
# paranoia level 1 and add rules from paranoia level 2 without having to fear
# the new rules would lead to false positives that raise your score above the
# threshold.
# This optional feature is enabled by uncommenting the following rule and
# setting the tx.detection_paranoia_level.
# Technically, rules up to the level defined in tx.detection_paranoia_level
# will be executed, but only the rules up to tx.blocking_paranoia_level affect the
# anomaly scores.
# By default, tx.detection_paranoia_level is set to tx.blocking_paranoia_level.
# tx.detection_paranoia_level must not be lower than tx.blocking_paranoia_level.
#
# Please notice that setting tx.detection_paranoia_level to a higher paranoia
# level results in a performance impact that is equally high as setting
# tx.blocking_paranoia_level to said level.
#
#SecAction \
# "id:900001,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.detection_paranoia_level=1"
#
# -- [[ Enforce Body Processor URLENCODED ]] -----------------------------------
#
# ModSecurity selects the body processor based on the Content-Type request
# header. But clients are not always setting the Content-Type header for their
# request body payloads. This will leave ModSecurity with limited vision into
# the payload. The variable tx.enforce_bodyproc_urlencoded lets you force the
# URLENCODED body processor in these situations. This is off by default, as it
# implies a change of the behaviour of ModSecurity beyond CRS (the body
# processor applies to all rules, not only CRS) and because it may lead to
# false positives already on paranoia level 1. However, enabling this variable
# closes a possible bypass of CRS so it should be considered.
#
# Uncomment this rule to change the default:
#
#SecAction \
# "id:900010,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.enforce_bodyproc_urlencoded=1"
#
# -- [[ Anomaly Scoring Mode Severity Levels ]] --------------------------------
#
# Each rule in the CRS has an associated severity level.
# These are the default scoring points for each severity level.
# These settings will be used to increment the anomaly score if a rule matches.
# You may adjust these points to your liking, but this is usually not needed.
#
# - CRITICAL severity: Anomaly Score of 5.
# Mostly generated by the application attack rules (93x and 94x files).
# - ERROR severity: Anomaly Score of 4.
# Generated mostly from outbound leakage rules (95x files).
# - WARNING severity: Anomaly Score of 3.
# Generated mostly by malicious client rules (91x files).
# - NOTICE severity: Anomaly Score of 2.
# Generated mostly by the protocol rules (92x files).
#
# In anomaly mode, these scores are cumulative.
# So it's possible for a request to hit multiple rules.
#
# (Note: In this file, we use 'phase:1' to set CRS configuration variables.
# In general, 'phase:request' is used. However, we want to make absolutely sure
# that all configuration variables are set before the CRS rules are processed.)
#
#SecAction \
# "id:900100,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.critical_anomaly_score=5,\
# setvar:tx.error_anomaly_score=4,\
# setvar:tx.warning_anomaly_score=3,\
# setvar:tx.notice_anomaly_score=2"
#
# -- [[ Anomaly Scoring Mode Blocking Threshold Levels ]] ----------------------
#
# Here, you can specify at which cumulative anomaly score an inbound request,
# or outbound response, gets blocked.
#
# Most detected inbound threats will give a critical score of 5.
# Smaller violations, like violations of protocol/standards, carry lower scores.
#
# [ At default value ]
# If you keep the blocking thresholds at the defaults, the CRS will work
# similarly to previous CRS versions: a single critical rule match will cause
# the request to be blocked and logged.
#
# [ Using higher values ]
# If you want to make the CRS less sensitive, you can increase the blocking
# thresholds, for instance to 7 (which would require multiple rule matches
# before blocking) or 10 (which would require at least two critical alerts - or
# a combination of many lesser alerts), or even higher. However, increasing the
# thresholds might cause some attacks to bypass the CRS rules or your policies.
#
# [ New deployment strategy: Starting high and decreasing ]
# It is a common practice to start a fresh CRS installation with elevated
# anomaly scoring thresholds (>100) and then lower the limits as your
# confidence in the setup grows. You may also look into the Sampling
# Percentage section below for a different strategy to ease into a new
# CRS installation.
#
# [ Anomaly Threshold / Paranoia Level Quadrant ]
#
# High Anomaly Limit | High Anomaly Limit
# Low Paranoia Level | High Paranoia Level
# -> Fresh Site | -> Experimental Site
# ------------------------------------------------------
# Low Anomaly Limit | Low Anomaly Limit
# Low Paranoia Level | High Paranoia Level
# -> Standard Site | -> High Security Site
#
# Uncomment this rule to change the defaults:
#
#SecAction \
# "id:900110,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.inbound_anomaly_score_threshold=5,\
# setvar:tx.outbound_anomaly_score_threshold=4"
#
# -- [[ Application Specific Rule Exclusions ]] --------------------------------
#
# CRS 3.x contained exclusion packages to tweak the CRS for use with common
# web applications, lowering the number of false positives.
#
# In CRS 4, these are no longer part of the CRS itself, but they are available
# as "CRS plugins". Some plugins improve support for web applications, and others
# may bring new functionality. Plugins are not installed by default, but can be
# downloaded from the plugin registry:
# https://github.com/coreruleset/plugin-registry
#
# For detailed information about using and installing plugins, please see:
# https://coreruleset.org/docs/configuring/plugins/
#
# -- [[ Anomaly Score Reporting Level ]] ---------------------------------------
#
# When a request is blocked due to the anomaly score meeting or exceeding the
# anomaly threshold then the blocking rule will also report the anomaly score.
# This applies to the separate inbound and outbound anomaly scores.
#
# In phase 5, there are additional rules that can perform additional reporting
# of anomaly scores with a verbosity that depends on the reporting level defined
# below.
#
# By setting the reporting level you control whether you want additional
# reporting beyond the blocking rule or not and, if yes, which requests should
# be covered. The higher the reporting level, the more verbose the reporting is.
#
# There are 6 reporting levels:
#
# 0 - Reporting disabled
# 1 - Reporting for requests with a blocking anomaly score >= a threshold
# 2 - Reporting for requests with a detection anomaly score >= a threshold
# 3 - Reporting for requests with a blocking anomaly score greater than 0
# 4 - Reporting for requests with a detection anomaly score greater than 0
# 5 - Reporting for all requests
#
# Note: Reporting levels 1 and 2 make it possible to differentiate between
# requests that are blocked and requests that are *not* blocked but would have
# been blocked if the blocking PL was equal to detection PL. This may be useful
# for certain FP tuning methodologies, for example moving to a higher PL.
#
# A value of 5 can be useful on platforms where you are interested in logging
# non-scoring requests, yet it is not possible to report this information in
# the request/access log. This applies to Nginx, for example.
#
#SecAction \
# "id:900115,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.reporting_level=4"
#
# -- [[ Early Anomaly Scoring Mode Blocking ]] ------------------------------
#
# The anomaly scores for the request and the responses are generally summed up
# and evaluated at the end of phase:2 and at the end of phase:4 respectively.
# However, it is possible to enable an early evaluation of these anomaly scores
# at the end of phase:1 and at the end of phase:3.
#
# If a request (or a response) hits the anomaly threshold in this early
# evaluation, then blocking happens immediately (if blocking is enabled) and
# the phase 2 (and phase 4 respectively) will no longer be executed.
#
# Enable the rule 900120 that sets the variable tx.early_blocking to 1 in order
# to enable early blocking. The variable tx.early_blocking is set to 0 by
# default. Early blocking is thus disabled by default.
#
# Please note that early blocking will hide potential alerts from you. This
# means that a payload that would appear in an alert in phase 2 (or phase 4)
# does not get evaluated if the request is being blocked early. So when you
# disabled early blocking again at some point in the future, then new alerts
# from phase 2 might pop up.
#SecAction \
# "id:900120,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.early_blocking=1"
#
# -- [[ HTTP Policy Settings ]] ------------------------------------------------
#
# This section defines your policies for the HTTP protocol, such as:
# - allowed HTTP versions, HTTP methods, allowed request Content-Types
# - forbidden file extensions (e.g. .bak, .sql) and request headers (e.g. Proxy)
#
# These variables are used in the following rule files:
# - REQUEST-911-METHOD-ENFORCEMENT.conf
# - REQUEST-920-PROTOCOL-ENFORCEMENT.conf
# HTTP methods that a client is allowed to use.
# Default: GET HEAD POST OPTIONS
# Example: for RESTful APIs, add the following methods: PUT PATCH DELETE
# Example: for WebDAV, add the following methods: CHECKOUT COPY DELETE LOCK
# MERGE MKACTIVITY MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK
# Uncomment this rule to change the default.
#SecAction \
# "id:900200,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'"
# Content-Types that a client is allowed to send in a request.
# Default: |application/x-www-form-urlencoded| |multipart/form-data| |multipart/related|
# |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json|
# |application/cloudevents+json| |application/cloudevents-batch+json| |application/octet-stream|
# |application/csp-report| |application/xss-auditor-report| |text/plain|
# Uncomment this rule to change the default.
#
# Please note, that the rule where CRS uses this variable (920420) evaluates it with operator
# `@within`, which is case sensitive, but uses t:lowercase. You must add your whole custom
# Content-Type with lowercase.
#
#SecAction \
# "id:900220,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| |application/cloudevents+json| |application/cloudevents-batch+json| |application/octet-stream| |application/csp-report| |application/xss-auditor-report| |text/plain|'"
# Allowed HTTP versions.
# Default: HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0
# Example for legacy clients: HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0
# Note that some web server versions use 'HTTP/2', some 'HTTP/2.0', so
# we include both version strings by default.
# Uncomment this rule to change the default.
#SecAction \
# "id:900230,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0'"
# Forbidden file extensions.
# Guards against unintended exposure of development/configuration files.
# Default: .asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .rdb/ .resources/ .resx/ .sql/ .swp/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/
# Example: .bak/ .config/ .conf/ .db/ .ini/ .log/ .old/ .pass/ .pdb/ .rdb/ .sql/
# Uncomment this rule to change the default.
#SecAction \
# "id:900240,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .rdb/ .resources/ .resx/ .sql/ .swp/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/'"
# Forbidden request headers.
# Header names should be lowercase, enclosed by /slashes/ as delimiters.
# Blocking Proxy header prevents 'httpoxy' vulnerability: https://httpoxy.org
# Default: /proxy/ /lock-token/ /content-range/ /if/ /user-agentt/
# Uncomment this rule to change the default.
#SecAction \
# "id:900250,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:'tx.restricted_headers=/proxy/ /lock-token/ /content-range/ /if/ /user-agentt/'"
# Content-Types charsets that a client is allowed to send in a request.
# The content-types are enclosed by |pipes| as delimiters to guarantee exact matches.
# Default: |utf-8| |iso-8859-1| |iso-8859-15| |windows-1252|
# Uncomment this rule to change the default.
#SecAction \
# "id:900280,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:'tx.allowed_request_content_type_charset=|utf-8| |iso-8859-1| |iso-8859-15| |windows-1252|'"
#
# -- [[ HTTP Argument/Upload Limits ]] -----------------------------------------
#
# Here you can define optional limits on HTTP get/post parameters and uploads.
# This can help to prevent application specific DoS attacks.
#
# These values are checked in REQUEST-920-PROTOCOL-ENFORCEMENT.conf.
# Beware of blocking legitimate traffic when enabling these limits.
#
# Block request if number of arguments is too high
# Default: unlimited
# Example: 255
# Uncomment this rule to set a limit.
#SecAction \
# "id:900300,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.max_num_args=255"
# Block request if the length of any argument name is too high
# Default: unlimited
# Example: 100
# Uncomment this rule to set a limit.
#SecAction \
# "id:900310,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.arg_name_length=100"
# Block request if the length of any argument value is too high
# Default: unlimited
# Example: 400
# Uncomment this rule to set a limit.
#SecAction \
# "id:900320,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.arg_length=400"
# Block request if the total length of all combined arguments is too high
# Default: unlimited
# Example: 64000
# Uncomment this rule to set a limit.
#SecAction \
# "id:900330,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.total_arg_length=64000"
# Block request if the file size of any individual uploaded file is too high
# Default: unlimited
# Example: 1048576
# Uncomment this rule to set a limit.
#SecAction \
# "id:900340,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.max_file_size=1048576"
# Block request if the total size of all combined uploaded files is too high
# Default: unlimited
# Example: 1048576
# Uncomment this rule to set a limit.
#SecAction \
# "id:900350,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.combined_file_sizes=1048576"
#
# -- [[ Easing In / Sampling Percentage ]] -------------------------------------
#
# Adding the Core Rule Set to an existing productive site can lead to false
# positives, unexpected performance issues and other undesired side effects.
#
# It can be beneficial to test the water first by enabling the CRS for a
# limited number of requests only and then, when you have solved the issues (if
# any) and you have confidence in the setup, to raise the ratio of requests
# being sent into the ruleset.
#
# Adjust the percentage of requests that are funnelled into the Core Rules by
# setting TX.sampling_percentage below. The default is 100, meaning that every
# request gets checked by the CRS. The selection of requests, which are going
# to be checked, is based on a pseudo random number generated by ModSecurity.
#
# If a request is allowed to pass without being checked by the CRS, there is no
# entry in the audit log (for performance reasons), but an error log entry is
# written. If you want to disable the error log entry, then issue the
# following directive somewhere after the inclusion of the CRS
# (E.g., RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf).
#
# SecRuleUpdateActionById 901450 "nolog"
#
# ATTENTION: If this TX.sampling_percentage is below 100, then some of the
# requests will bypass the Core Rules completely and you lose the ability to
# protect your service with ModSecurity.
#
# Uncomment this rule to enable this feature:
#
#SecAction "id:900400,\
# phase:1,\
# pass,\
# nolog,\
# setvar:tx.sampling_percentage=100"
#
# -- [[ Check UTF-8 encoding ]] ------------------------------------------------
#
# The CRS can optionally check request contents for invalid UTF-8 encoding.
# We only want to apply this check if UTF-8 encoding is actually used by the
# site; otherwise it will result in false positives.
#
# Uncomment this rule to use this feature:
#
#SecAction \
# "id:900950,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.crs_validate_utf8_encoding=1"
#
# -- [[ Collection timeout ]] --------------------------------------------------
#
# Set the SecCollectionTimeout directive from the ModSecurity default (1 hour)
# to a lower setting which is appropriate to most sites.
# This increases performance by cleaning out stale collection (block) entries.
#
# This value should be greater than or equal to any block durations or timeouts
# set by plugins that make use of ModSecurity's persistent collections (e.g. the
# DoS protection and IP reputation plugins).
#
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#SecCollectionTimeout
# Please keep this directive uncommented.
# Default: 600 (10 minutes)
SecCollectionTimeout 600
#
# -- [[ End of setup ]] --------------------------------------------------------
#
# The CRS checks the tx.crs_setup_version variable to ensure that the setup
# has been loaded. If you are not planning to use this setup template,
# you must manually set the tx.crs_setup_version variable before including
# the CRS rules/* files.
#
# The variable is a numerical representation of the CRS version number.
# E.g., v3.0.0 is represented as 300.
#
SecAction \
"id:900990,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.crs_setup_version=400"
Include /usr/share/owasp-modsecurity-crs/rules/*.conf

View File

@ -6,6 +6,8 @@ error_log logs/error.log;
error_log logs/error.log notice; error_log logs/error.log notice;
error_log logs/error.log info; error_log logs/error.log info;
load_module /usr/lib/nginx/modules/ngx_http_modsecurity_module.so;
events { events {
worker_connections 1024; worker_connections 1024;
} }
@ -31,7 +33,8 @@ http {
location / { location / {
return 301 https://$host$request_uri; return 301 https://$host$request_uri;
} }
} }
include ../conf.d/*.conf; include conf.d/*.conf;
} }

View File

@ -1,11 +1,14 @@
--- ---
- name: Install openresty - name: Install components
become: yes become: yes
package: package:
name: "{{ item }}" name: "{{ item }}"
state: present state: present
loop: loop:
- openresty - nginx
- libmodsecurity
- nginx-mod-modsecurity
- php
- php-fpm - php-fpm
- name: Copy PHP config - name: Copy PHP config
@ -17,26 +20,11 @@
group: root group: root
mode: 0755 mode: 0755
- name: Copy Webserver config
become: yes
copy:
src: webserver.service
dest: /usr/lib/systemd/system/webserver.service
owner: http
group: http
mode: 0660
register: servicefile
- systemd:
daemon_reload: true
when: servicefile.changed
become: yes
- name: Copy conf.d - name: Copy conf.d
become: yes become: yes
copy: copy:
src: "conf.d/{{ inventory_hostname }}/" src: "conf.d/{{ inventory_hostname }}/"
dest: /opt/openresty/nginx/conf.d/ dest: /etc/nginx/conf.d/
owner: http owner: http
group: http group: http
mode: 0660 mode: 0660
@ -48,38 +36,108 @@
become: yes become: yes
copy: copy:
src: conf/ src: conf/
dest: /opt/openresty/nginx/conf/ dest: /etc/nginx/conf/
owner: http owner: http
group: http group: http
mode: 0660 mode: 0660
follow: true follow: true
register: conf register: conf
- name: Nginx pidfile
become: yes
ignore_errors: true
file:
path: /run/nginx.pid
state: file
owner: http
group: http
mode: 0640
- name: Nginx log folder
become: yes
file:
path: /var/log/nginx
state: directory
owner: http
group: http
mode: 0750
- name: Populate security config - name: Populate security config
become: yes become: yes
template: template:
src: conf/sec.conf.j2 src: conf/sec.conf.j2
dest: /opt/openresty/nginx/conf/sec.conf dest: /etc/nginx/conf/sec.conf
owner: http owner: http
group: http group: http
mode: 0660 mode: 0660
register: secconf register: secconf
- name: Clone OWASP-CRS
- name: Ensure default openresty service file is off. ignore_errors: true
become: yes become: yes
service: git:
name: openresty repo: https://github.com/coreruleset/coreruleset.git
state: stopped update: yes
enabled: no force: yes
single_branch: yes
dest: /usr/share/owasp-modsecurity-crs
umask: "0022"
- name: Modsecurity config dir
become: yes
file:
path: "{{ item }}"
state: directory
owner: http
group: http
mode: 0750
loop:
- /etc/modsecurity
- /var/log/modsec
- /var/log/modsec/tmp
- /var/log/modsec/data
- /var/log/modsec/audit
- /var/log/modsec/uploads
- name: Modsecurity config
become: yes
register: modsecconf
copy:
dest: /etc/modsecurity/main.conf
src: modsec.conf
owner: http
group: http
mode: 0750
validate: /usr/bin/modsec-rules-check %s
- name: Modsecurity logrotate
become: yes
copy:
dest: /etc/logrotate.d/modsecurity
src: logrotate.modsec.conf
owner: root
group: root
mode: 0644
- name: Copy conf
become: yes
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: http
group: http
mode: 0660
follow: true
#validate: nginx -t -p /etc/nginx -c %s # Commented due to base pathing issues
register: baseconf
- name: Ensure service is started - name: Ensure service is started
become: yes become: yes
when: conf.changed or confd.changed or secconf.changed when: conf.changed or confd.changed or secconf.changed or baseconf.changed or modsecconf.changed
service: service:
name: "{{ item }}" name: "{{ item }}"
enabled: yes enabled: yes
state: restarted state: restarted
loop: loop:
- php-fpm - php-fpm
- webserver - nginx

View File

@ -11,12 +11,15 @@ ssl_prefer_server_ciphers on;
add_header "Strict-Transport-Security" "max-age=63072000; includeSubDomains; preload"; add_header "Strict-Transport-Security" "max-age=63072000; includeSubDomains; preload";
add_header "X-Content-Type-Options" "nosniff"; add_header "X-Content-Type-Options" "nosniff";
add_header "Public-Key-Pins" "pin-sha256=\"JYR9Zo608E/dQLErawdAxWfafQJDCOtsLJb+QdneIY0=\"; max-age=315360000; includeSubDomains"; add_header "Public-Key-Pins" "pin-sha256=\"sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis=\"; pin-sha256=\"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=\"; pin-sha256=\"C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=\"; max-age=60; includeSubDomains";
add_header "X-XSS-Protection" "1; mode=block"; add_header "X-XSS-Protection" "1; mode=block";
add_header "X-Frame-Options" "SAMEORIGIN";
# Cross-Origin Resource Sharing # Cross-Origin Resource Sharing
# add_header 'Access-Control-Allow-Origin' '*' always; # add_header 'Access-Control-Allow-Origin' '*' always;
# add_header 'Access-Control-Allow_Credentials' 'true' always; # add_header 'Access-Control-Allow_Credentials' 'true' always;
# add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always; # add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;
# add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH' always; # add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH' always;
# ModSecurity WAF
modsecurity on;
modsecurity_rules_file /etc/modsecurity/main.conf;