Skip to content

Commit d4f2c71

Browse files
committed
Fixes #4
Added modsecurity example
1 parent f842fc2 commit d4f2c71

File tree

8 files changed

+1291
-1
lines changed

8 files changed

+1291
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ and caching gateway for read-only requests (GET/HEAD) to the S3 API.
1515
* Compressing objects ([gzip](examples/gzip-compression), [brotli](examples/brotli-compression)) from gateway to end user
1616
* Protecting S3 bucket from arbitrary public access and traversal
1717
* Rate limiting S3 objects
18-
* Protecting S3 bucket with a WAF in order to prevent asset discovery attacks
18+
* Protecting S3 bucket with a [WAF](examples/modsecurity)
1919
* Serving static assets from a S3 bucket alongside a dynamic application
2020
endpoints all in a single RESTful directory structure
2121

examples/modsecurity/Dockerfile.oss

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
FROM nginxinc/nginx-s3-gateway
2+
3+
ENV MODSECURITY_VERSION "v1.0.1"
4+
ENV OWASP_RULESET_VERSION "v3.3.0"
5+
ENV OWASP_RULESET_CHECKSUM "1f4002b5cf941a9172b6250cea7e3465a85ef6ee"
6+
7+
# Build modsecurity module from source because there is no repository package
8+
# Download OWASP ruleset
9+
RUN set -eux \
10+
export DEBIAN_FRONTEND=noninteractive; \
11+
apt-get update -qq; \
12+
apt-get install -y -qq build-essential libpcre3-dev git libmodsecurity3 libmodsecurity-dev curl libdigest-sha-perl; \
13+
curl -o /tmp/nginx.tar.gz --retry 6 -Ls "http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz"; \
14+
mkdir /tmp/nginx /tmp/modsecurity; \
15+
tar -C /tmp/nginx --strip-components 1 -xzf /tmp/nginx.tar.gz; \
16+
curl -o /tmp/modsecurity.tar.gz --retry 6 -Ls "https://github.com/SpiderLabs/ModSecurity-nginx/archive/${MODSECURITY_VERSION}.tar.gz"; \
17+
tar -C "/tmp/modsecurity" --strip-components 1 -xzf /tmp/modsecurity.tar.gz; \
18+
cd /tmp/nginx; \
19+
./configure --add-dynamic-module=/tmp/modsecurity \
20+
--without-http_gzip_module \
21+
--prefix=/etc/nginx \
22+
--sbin-path=/usr/sbin/nginx \
23+
--modules-path=/usr/lib/nginx/modules \
24+
--conf-path=/etc/nginx/nginx.conf \
25+
--error-log-path=/var/log/nginx/error.log \
26+
--http-log-path=/var/log/nginx/access.log \
27+
--pid-path=/var/run/nginx.pid \
28+
--lock-path=/var/run/nginx.lock \
29+
--http-client-body-temp-path=/var/cache/nginx/client_temp \
30+
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
31+
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
32+
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
33+
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
34+
--user=nginx --group=nginx --with-compat --with-file-aio \
35+
--with-threads \
36+
--with-compat \
37+
--with-cc-opt="-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-${NGINX_VERSION}/debian/debuild-base/nginx-${NGINX_VERSION}=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC" \
38+
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'; \
39+
make -j $(nproc) modules; \
40+
cp /tmp/nginx/objs/ngx_http_modsecurity_module.so /usr/lib/nginx/modules; \
41+
curl -o /tmp/coreruleset.tar.gz --retry 6 -Ls "https://github.com/coreruleset/coreruleset/archive/${OWASP_RULESET_VERSION}.tar.gz"; \
42+
echo "${OWASP_RULESET_CHECKSUM} /tmp/coreruleset.tar.gz" | shasum -c; \
43+
mkdir -p /usr/local/nginx/conf/owasp-modsecurity-crs; \
44+
tar -C /usr/local/nginx/conf/owasp-modsecurity-crs --strip-components 1 -xzf /tmp/coreruleset.tar.gz; \
45+
apt-get purge -y --auto-remove build-essential libpcre3-dev git libmodsecurity-dev curl libdigest-sha-perl; \
46+
rm -rf /var/lib/apt/lists/* /var/tmp/* /tmp/*
47+
48+
# Update configuration to load module
49+
RUN sed -i '1s#^#load_module modules/ngx_http_modsecurity_module.so;\n#' /etc/nginx/nginx.conf
50+
51+
# Update configuration to include modsecurity
52+
RUN sed -i 's#server {#server \{\n include /etc/nginx/conf.d/gateway/modsecurity.conf;#' /etc/nginx/templates/default.conf.template
53+
54+
COPY etc/nginx /etc/nginx
55+
COPY usr/local /usr/local

examples/modsecurity/Dockerfile.plus

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM nginx-plus-s3-gateway
2+
3+
ENV OWASP_RULESET_VERSION "v3.3.0"
4+
ENV OWASP_RULESET_CHECKSUM "1f4002b5cf941a9172b6250cea7e3465a85ef6ee"
5+
6+
# Install modsecurity from the NGINX Plus repository and download OWASP ruleset
7+
RUN set -eux \
8+
export DEBIAN_FRONTEND=noninteractive; \
9+
apt-get -qq update; \
10+
apt-get -qq install --no-install-recommends --no-install-suggests -y curl libdigest-sha-perl nginx-plus-module-modsecurity; \
11+
curl -o /tmp/coreruleset.tar.gz --retry 6 -Ls "https://github.com/coreruleset/coreruleset/archive/${OWASP_RULESET_VERSION}.tar.gz"; \
12+
echo "${OWASP_RULESET_CHECKSUM} /tmp/coreruleset.tar.gz" | shasum -c; \
13+
mkdir -p /usr/local/nginx/conf/owasp-modsecurity-crs; \
14+
tar -C /usr/local/nginx/conf/owasp-modsecurity-crs --strip-components 1 -xzf /tmp/coreruleset.tar.gz; \
15+
apt-get -qq purge curl libdigest-sha-perl; \
16+
rm -rf /var/lib/apt/lists/*
17+
18+
# Update configuration to load module
19+
RUN sed -i '1s#^#load_module modules/ngx_http_modsecurity_module.so;\n#' /etc/nginx/nginx.conf
20+
21+
# Update configuration to include modsecurity
22+
RUN sed -i 's#server {#server \{\n include /etc/nginx/conf.d/gateway/modsecurity.conf;#' /etc/nginx/templates/default.conf.template
23+
24+
COPY etc/nginx /etc/nginx
25+
COPY usr/local /usr/local
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
modsecurity on;
2+
modsecurity_rules_file /etc/nginx/modsec/main.conf;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Include the recommended configuration
2+
Include modsecurity.conf
3+
4+
# Rules from OWASP ruleset
5+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/crs-setup.conf
6+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf
7+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
8+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf
9+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf
10+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf
11+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
12+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf
13+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf
14+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf
15+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
16+
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# -- Rule engine initialization ----------------------------------------------
2+
3+
# Enable ModSecurity, attaching it to every transaction. Use detection
4+
# only to start with, because that minimises the chances of post-installation
5+
# disruption.
6+
#
7+
SecRuleEngine On
8+
9+
10+
# -- Request body handling ---------------------------------------------------
11+
12+
# Allow ModSecurity to access request bodies. If you don't, ModSecurity
13+
# won't be able to see any POST parameters, which opens a large security
14+
# hole for attackers to exploit.
15+
#
16+
SecRequestBodyAccess On
17+
18+
19+
# Enable XML request body parser.
20+
# Initiate XML Processor in case of xml content-type
21+
#
22+
SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
23+
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
24+
25+
# Enable JSON request body parser.
26+
# Initiate JSON Processor in case of JSON content-type; change accordingly
27+
# if your application does not use 'application/json'
28+
#
29+
SecRule REQUEST_HEADERS:Content-Type "application/json" \
30+
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
31+
32+
# Maximum request body size we will accept for buffering. If you support
33+
# file uploads then the value given on the first line has to be as large
34+
# as the largest file you are willing to accept. The second value refers
35+
# to the size of data, with files excluded. You want to keep that value as
36+
# low as practical.
37+
#
38+
SecRequestBodyLimit 13107200
39+
SecRequestBodyNoFilesLimit 131072
40+
41+
# What do do if the request body size is above our configured limit.
42+
# Keep in mind that this setting will automatically be set to ProcessPartial
43+
# when SecRuleEngine is set to DetectionOnly mode in order to minimize
44+
# disruptions when initially deploying ModSecurity.
45+
#
46+
SecRequestBodyLimitAction Reject
47+
48+
# Verify that we've correctly processed the request body.
49+
# As a rule of thumb, when failing to process a request body
50+
# you should reject the request (when deployed in blocking mode)
51+
# or log a high-severity alert (when deployed in detection-only mode).
52+
#
53+
SecRule REQBODY_ERROR "!@eq 0" \
54+
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
55+
56+
# By default be strict with what we accept in the multipart/form-data
57+
# request body. If the rule below proves to be too strict for your
58+
# environment consider changing it to detection-only. You are encouraged
59+
# _not_ to remove it altogether.
60+
#
61+
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
62+
"id:'200003',phase:2,t:none,log,deny,status:400, \
63+
msg:'Multipart request body failed strict validation: \
64+
PE %{REQBODY_PROCESSOR_ERROR}, \
65+
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
66+
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
67+
DB %{MULTIPART_DATA_BEFORE}, \
68+
DA %{MULTIPART_DATA_AFTER}, \
69+
HF %{MULTIPART_HEADER_FOLDING}, \
70+
LF %{MULTIPART_LF_LINE}, \
71+
SM %{MULTIPART_MISSING_SEMICOLON}, \
72+
IQ %{MULTIPART_INVALID_QUOTING}, \
73+
IP %{MULTIPART_INVALID_PART}, \
74+
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
75+
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
76+
77+
# Did we see anything that might be a boundary?
78+
#
79+
# Here is a short description about the ModSecurity Multipart parser: the
80+
# parser returns with value 0, if all "boundary-like" line matches with
81+
# the boundary string which given in MIME header. In any other cases it returns
82+
# with different value, eg. 1 or 2.
83+
#
84+
# The RFC 1341 descript the multipart content-type and its syntax must contains
85+
# only three mandatory lines (above the content):
86+
# * Content-Type: multipart/mixed; boundary=BOUNDARY_STRING
87+
# * --BOUNDARY_STRING
88+
# * --BOUNDARY_STRING--
89+
#
90+
# First line indicates, that this is a multipart content, second shows that
91+
# here starts a part of the multipart content, third shows the end of content.
92+
#
93+
# If there are any other lines, which starts with "--", then it should be
94+
# another boundary id - or not.
95+
#
96+
# After 3.0.3, there are two kinds of types of boundary errors: strict and permissive.
97+
#
98+
# If multipart content contains the three necessary lines with correct order, but
99+
# there are one or more lines with "--", then parser returns with value 2 (non-zero).
100+
#
101+
# If some of the necessary lines (usually the start or end) misses, or the order
102+
# is wrong, then parser returns with value 1 (also a non-zero).
103+
#
104+
# You can choose, which one is what you need. The example below contains the
105+
# 'strict' mode, which means if there are any lines with start of "--", then
106+
# ModSecurity blocked the content. But the next, commented example contains
107+
# the 'permissive' mode, then you check only if the necessary lines exists in
108+
# correct order. Whit this, you can enable to upload PEM files (eg "----BEGIN.."),
109+
# or other text files, which contains eg. HTTP headers.
110+
#
111+
# The difference is only the operator - in strict mode (first) the content blocked
112+
# in case of any non-zero value. In permissive mode (second, commented) the
113+
# content blocked only if the value is explicit 1. If it 0 or 2, the content will
114+
# allowed.
115+
#
116+
117+
#
118+
# See #1747 and #1924 for further information on the possible values for
119+
# MULTIPART_UNMATCHED_BOUNDARY.
120+
#
121+
SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \
122+
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
123+
124+
125+
# PCRE Tuning
126+
# We want to avoid a potential RegEx DoS condition
127+
#
128+
SecPcreMatchLimit 1000
129+
SecPcreMatchLimitRecursion 1000
130+
131+
# Some internal errors will set flags in TX and we will need to look for these.
132+
# All of these are prefixed with "MSC_". The following flags currently exist:
133+
#
134+
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
135+
#
136+
SecRule TX:/^MSC_/ "!@streq 0" \
137+
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
138+
139+
140+
# -- Response body handling --------------------------------------------------
141+
142+
# Allow ModSecurity to access response bodies.
143+
# You should have this directive enabled in order to identify errors
144+
# and data leakage issues.
145+
#
146+
# Do keep in mind that enabling this directive does increases both
147+
# memory consumption and response latency.
148+
#
149+
SecResponseBodyAccess On
150+
151+
# Which response MIME types do you want to inspect? You should adjust the
152+
# configuration below to catch documents but avoid static files
153+
# (e.g., images and archives).
154+
#
155+
SecResponseBodyMimeType text/plain text/html text/xml
156+
157+
# Buffer response bodies of up to 512 KB in length.
158+
SecResponseBodyLimit 524288
159+
160+
# What happens when we encounter a response body larger than the configured
161+
# limit? By default, we process what we have and let the rest through.
162+
# That's somewhat less secure, but does not break any legitimate pages.
163+
#
164+
SecResponseBodyLimitAction ProcessPartial
165+
166+
167+
# -- Filesystem configuration ------------------------------------------------
168+
169+
# The location where ModSecurity stores temporary files (for example, when
170+
# it needs to handle a file upload that is larger than the configured limit).
171+
#
172+
# This default setting is chosen due to all systems have /tmp available however,
173+
# this is less than ideal. It is recommended that you specify a location that's private.
174+
#
175+
SecTmpDir /tmp/
176+
177+
# The location where ModSecurity will keep its persistent data. This default setting
178+
# is chosen due to all systems have /tmp available however, it
179+
# too should be updated to a place that other users can't access.
180+
#
181+
SecDataDir /var/tmp/
182+
183+
184+
# -- File uploads handling configuration -------------------------------------
185+
186+
# The location where ModSecurity stores intercepted uploaded files. This
187+
# location must be private to ModSecurity. You don't want other users on
188+
# the server to access the files, do you?
189+
#
190+
#SecUploadDir /opt/modsecurity/var/upload/
191+
192+
# By default, only keep the files that were determined to be unusual
193+
# in some way (by an external inspection script). For this to work you
194+
# will also need at least one file inspection rule.
195+
#
196+
#SecUploadKeepFiles RelevantOnly
197+
198+
# Uploaded files are by default created with permissions that do not allow
199+
# any other user to access them. You may need to relax that if you want to
200+
# interface ModSecurity to an external program (e.g., an anti-virus).
201+
#
202+
#SecUploadFileMode 0600
203+
204+
205+
# -- Debug log configuration -------------------------------------------------
206+
207+
# The default debug log configuration is to duplicate the error, warning
208+
# and notice messages from the error log.
209+
#
210+
#SecDebugLog /opt/modsecurity/var/log/debug.log
211+
#SecDebugLogLevel 3
212+
213+
214+
# -- Audit log configuration -------------------------------------------------
215+
216+
# Log the transactions that are marked by a rule, as well as those that
217+
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
218+
# level response status codes).
219+
#
220+
SecAuditEngine RelevantOnly
221+
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
222+
223+
# Log everything we know about a transaction.
224+
SecAuditLogParts ABIJDEFHZ
225+
226+
# Use a single file for logging. This is much easier to look at, but
227+
# assumes that you will use the audit log only ocassionally.
228+
#
229+
SecAuditLogType Serial
230+
#SecAuditLog /var/log/modsec_audit.log
231+
SecAuditLog /dev/stdout
232+
233+
# Specify the path for concurrent audit logging.
234+
#SecAuditLogStorageDir /opt/modsecurity/var/audit/
235+
236+
237+
# -- Miscellaneous -----------------------------------------------------------
238+
239+
# Use the most commonly used application/x-www-form-urlencoded parameter
240+
# separator. There's probably only one application somewhere that uses
241+
# something else so don't expect to change this value.
242+
#
243+
SecArgumentSeparator &
244+
245+
# Settle on version 0 (zero) cookies, as that is what most applications
246+
# use. Using an incorrect cookie version may open your installation to
247+
# evasion attacks (against the rules that examine named cookies).
248+
#
249+
SecCookieFormat 0
250+
251+
# Specify your Unicode Code Point.
252+
# This mapping is used by the t:urlDecodeUni transformation function
253+
# to properly map encoded data to your language. Properly setting
254+
# these directives helps to reduce false positives and negatives.
255+
#
256+
SecUnicodeMapFile unicode.mapping 20127
257+
258+
# Improve the quality of ModSecurity by sharing information about your
259+
# current ModSecurity version and dependencies versions.
260+
# The following information will be shared: ModSecurity version,
261+
# Web Server version, APR version, PCRE version, Lua version, Libxml2
262+
# version, Anonymous unique id for host.
263+
SecStatusEngine On
264+

0 commit comments

Comments
 (0)