Remove unused test files and scripts from ModSecurity Nginx integration

This commit is contained in:
Théophile Diot 2025-01-16 10:32:57 +01:00
parent 3a7a25b568
commit ba242318bd
No known key found for this signature in database
GPG key ID: FA995104A0BA376A
16 changed files with 0 additions and 2603 deletions

View file

@ -1,10 +0,0 @@
# Tests
Those are nginx test files. You can copy those files into yours nginx test
tree, to perform the tests using the "prove" utility.
For more information about those tests, read the subsection "Testing your
patch" on the project's README file.
For more about nginx tests, check their repository:
http://hg.nginx.org/nginx-tests/

View file

@ -1,233 +0,0 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
location / {
modsecurity_rules '
SecRule ARGS "@streq root" "id:21,phase:1,auditlog,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-root.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts AB
SecAuditLog %%TESTDIR%%/auditlog-root.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder1/subfolder2 {
modsecurity_rules '
SecRule ARGS "@streq subfolder2" "id:41,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq subfolder1" "id:42,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder2.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts AB
SecResponseBodyAccess On
SecAuditLog %%TESTDIR%%/auditlog-subfolder2.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder1 {
modsecurity_rules '
SecRule ARGS "@streq subfolder1" "id:31,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder1.txt
SecDebugLogLevel 9
SecAuditLogParts AB
SecAuditEngine RelevantOnly
SecAuditLog %%TESTDIR%%/auditlog-subfolder1.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder3/subfolder4 {
modsecurity_rules '
SecResponseBodyAccess On
SecRule ARGS "@streq subfolder4" "id:61,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq subfolder3" "id:62,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq subfolder4withE" "id:63,phase:1,ctl:auditLogParts=+E,auditlog"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder4.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts AB
SecAuditLog %%TESTDIR%%/auditlog-subfolder4.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder3 {
modsecurity_rules '
SecRule ARGS "@streq subfolder3" "id:51,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder3.txt
SecDebugLogLevel 9
SecAuditLogParts AB
SecAuditEngine RelevantOnly
SecAuditLog %%TESTDIR%%/auditlog-subfolder3.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
}
}
EOF
$t->write_file("/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1');
$t->write_file("/subfolder1/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1/subfolder2');
$t->write_file("/subfolder1/subfolder2/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder3');
$t->write_file("/subfolder3/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder3/subfolder4');
$t->write_file("/subfolder3/subfolder4/index.html", "should be moved/blocked before this.");
$t->run();
$t->plan(9);
###############################################################################
my $d = $t->testdir();
my $r;
# Performing requests at root
$r = http_get('/index.html?what=root');
$r = http_get('/index.html?what=subfolder1');
$r = http_get('/index.html?what=subfolder2');
$r = http_get('/index.html?what=subfolder3');
$r = http_get('/index.html?what=subfolder4');
# Performing requests at subfolder1
$r = http_get('/subfolder1/index.html?what=root');
$r = http_get('/subfolder1/index.html?what=subfolder1');
$r = http_get('/subfolder1/index.html?what=subfolder2');
$r = http_get('/subfolder1/index.html?what=subfolder3');
$r = http_get('/subfolder1/index.html?what=subfolder4');
# Performing requests at subfolder2
$r = http_get('/subfolder1/subfolder2/index.html?what=root');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder1');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder2');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder3');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder4');
# Performing requests at subfolder3
$r = http_get('/subfolder3/index.html?what=root');
$r = http_get('/subfolder3/index.html?what=subfolder1');
$r = http_get('/subfolder3/index.html?what=subfolder2');
$r = http_get('/subfolder3/index.html?what=subfolder3');
$r = http_get('/subfolder3/index.html?what=subfolder4');
# Performing requests at subfolder4
$r = http_get('/subfolder3/subfolder4/index.html?what=root');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder1');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder2');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder3');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder4');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder4withE');
my $root = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-root.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder1 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder1.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder2 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder2.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder3 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder3.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder4 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder4.txt"
or die "could not open: $!";
<$fh>;
};
like($root, qr/what=root/, 'root');
like($subfolder1, qr/what=subfolder1/, 'subfolder1');
like($subfolder2, qr/what=subfolder2/, 'subfolder2');
like($subfolder2, qr/what=subfolder1/, 'subfolder2 / subfolder1');
like($subfolder3, qr/what=subfolder3/, 'subfolder3');
like($subfolder4, qr/what=subfolder4/, 'subfolder4');
like($subfolder4, qr/what=subfolder3/, 'subfolder4 / subfolder3');
like($subfolder4, qr/what=subfolder4withE/, 'subfolder4');
like($subfolder4, qr/---E--/, 'subfolder4');

View file

@ -1,174 +0,0 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name s1;
error_page 403 /403.html;
location /403.html {
root %%TESTDIR%%/http;
internal;
}
location / {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq root" "id:10,phase:1,auditlog,status:403,deny"
SecDebugLog %%TESTDIR%%/auditlog-debug-local.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts ABIJDEFHZ
SecAuditLog %%TESTDIR%%/auditlog-local.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
}
server {
listen 127.0.0.1:8080;
server_name s2;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq root" "id:10,phase:1,auditlog,status:403,deny"
SecDebugLog %%TESTDIR%%/auditlog-debug-global.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts ABIJDEFHZ
SecAuditLog %%TESTDIR%%/auditlog-global.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
error_page 403 /403.html;
location /403.html {
modsecurity off;
root %%TESTDIR%%/http;
internal;
}
location / {
}
}
}
EOF
my $index_txt = "This is the index page.";
my $custom_txt = "This is a custom error page.";
$t->write_file("/index.html", $index_txt);
mkdir($t->testdir() . '/http');
$t->write_file("/http/403.html", $custom_txt);
$t->run();
$t->plan(10);
###############################################################################
my $d = $t->testdir();
my $t1;
my $t2;
my $t3;
my $t4;
# Performing requests to a server with ModSecurity enabled at location context
$t1 = http_get_host('s1', '/index.html?what=root');
$t2 = http_get_host('s1', '/index.html?what=other');
# Performing requests to a server with ModSecurity enabled at server context
$t3 = http_get_host('s2', '/index.html?what=root');
$t4 = http_get_host('s2', '/index.html?what=other');
my $local = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-local.txt"
or die "could not open: $!";
<$fh>;
};
my $global = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-global.txt"
or die "could not open: $!";
<$fh>;
};
like($t1, qr/$custom_txt/, 'ModSecurity at location / root');
like($t2, qr/$index_txt/, 'ModSecurity at location / other');
like($local, qr/what=root/, 'ModSecurity at location / root present in auditlog');
unlike($local, qr/what=other/, 'ModSecurity at location / other not present in auditlog');
like($t3, qr/$custom_txt/, 'ModSecurity at server / root');
like($t4, qr/$index_txt/, 'ModSecurity at server / other');
like($global, qr/what=root/, 'ModSecurity at server / root present in auditlog');
unlike($global, qr/what=other/, 'ModSecurity at server / other not present in auditlog');
like($local, qr/Access denied with code 403/, 'ModSecurity at location / 403 in auditlog');
like($global, qr/Access denied with code 403/, 'ModSecurity at server / 403 in auditlog');
###############################################################################
sub http_get_host {
my ($host, $url) = @_;
return http(<<EOF);
GET $url HTTP/1.0
Host: $host
EOF
}
###############################################################################

View file

@ -1,142 +0,0 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
location / {
modsecurity_rules '
SecRule ARGS "@streq root" "id:21,phase:1,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/debuglog-root.txt
SecDebugLogLevel 9
';
}
location /subfolder1 {
modsecurity_rules '
SecRule ARGS "@streq subfolder1" "id:31,phase:1,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/debuglog-subfolder1.txt
SecDebugLogLevel 9
';
location /subfolder1/subfolder2 {
modsecurity_rules '
SecRule ARGS "@streq subfolder2" "id:41,phase:1,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/debuglog-subfolder2.txt
SecDebugLogLevel 9
';
}
}
}
}
EOF
$t->write_file("/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1');
$t->write_file("/subfolder1/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1/subfolder2');
$t->write_file("/subfolder1/subfolder2/index.html", "should be moved/blocked before this.");
$t->run();
$t->plan(3);
###############################################################################
my $d = $t->testdir();
my $r;
# Performing requests at root
$r = http_get('/index.html?what=root');
$r = http_get('/index.html?what=subfolder1');
$r = http_get('/index.html?what=subfolder2');
# Performing requests at subfolder1
$r = http_get('/subfolder1/index.html?what=root');
$r = http_get('/subfolder1/index.html?what=subfolder1');
$r = http_get('/subfolder1/index.html?what=subfolder2');
# Performing requests at subfolder2
$r = http_get('/subfolder1/subfolder2/index.html?what=root');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder1');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder2');
my $root = do {
local $/ = undef;
open my $fh, "<", "$d/debuglog-root.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder1 = do {
local $/ = undef;
open my $fh, "<", "$d/debuglog-subfolder1.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder2 = do {
local $/ = undef;
open my $fh, "<", "$d/debuglog-subfolder2.txt"
or die "could not open: $!";
<$fh>;
};
like($root, qr/"what", value "root"/, 'root');
like($subfolder1, qr/"what", value "subfolder1"/, 'subfolder1');
like($subfolder2, qr/"what", value "subfolder2"/, 'subfolder2');

View file

@ -1,231 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (configuration merge).
###############################################################################
use warnings;
use strict;
use Test::More;
use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http proxy/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:11,phase:request,deny,log,status:403"
';
server {
listen 127.0.0.1:%%PORT_8080%%;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /modsec-disabled {
modsecurity_rules '
SecRuleEngine Off
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /nobodyaccess {
modsecurity_rules '
SecRequestBodyAccess Off
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitprocesspartial {
modsecurity_rules '
SecRequestBodyLimitAction ProcessPartial
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitincreased {
modsecurity_rules '
SecRequestBodyLimit 512
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /server {
modsecurity off;
location /server/modsec-disabled {
proxy_pass http://127.0.0.1:%%PORT_8082%%;
}
location /server/nobodyaccess {
proxy_pass http://127.0.0.1:%%PORT_8083%%;
}
location /server/bodylimitprocesspartial {
proxy_pass http://127.0.0.1:%%PORT_8084%%;
}
location /server/bodylimitincreased {
proxy_pass http://127.0.0.1:%%PORT_8085%%;
}
}
}
server {
listen 127.0.0.1:%%PORT_8082%%;
modsecurity_rules '
SecRuleEngine Off
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8083%%;
modsecurity_rules '
SecRequestBodyAccess Off
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8084%%;
modsecurity_rules '
SecRequestBodyLimitAction ProcessPartial
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8085%%;
modsecurity_rules '
SecRequestBodyLimit 512
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
}
EOF
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
$t->plan(10);
###############################################################################
like(http_get_body('/', 'GOOD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "http level defaults, pass");
like(http_get_body('/', 'VERY BAD BODY'), qr/^HTTP.*403/, "http level defaults, block");
like(http_get_body('/modsec-disabled', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRuleEngine, pass");
like(http_get_body('/nobodyaccess', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRequestBodyAccess, pass");
like(http_get_body('/bodylimitprocesspartial', 'BODY' x 33), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRequestBodyLimitAction, pass");
like(http_get_body('/bodylimitincreased', 'BODY' x 64), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRequestBodyLimit, pass");
like(http_get_body('/server/modsec-disabled', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRuleEngine, pass");
like(http_get_body('/server/nobodyaccess', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRequestBodyAccess, pass");
like(http_get_body('/server/bodylimitprocesspartial', 'BODY' x 33), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRequestBodyLimitAction, pass");
like(http_get_body('/server/bodylimitincreased', 'BODY' x 64), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRequestBodyLimit, pass");
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
close $client;
}
}
sub http_get_body {
my $uri = shift;
my $last = pop;
return http( join '', (map {
my $body = $_;
"GET $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Content-Length: " . (length $body) . CRLF . CRLF
. $body
} @_),
"GET $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Connection: close" . CRLF
. "Content-Length: " . (length $last) . CRLF . CRLF
. $last
);
}
###############################################################################

View file

@ -1,112 +0,0 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
location / {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq root" "id:21,phase:1,status:302,redirect:http://www.modsecurity.org"
';
}
location /subfolder1 {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq subfolder1" "id:31,phase:1,status:302,redirect:http://www.modsecurity.org"
';
location /subfolder1/subfolder2 {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq subfolder2" "id:41,phase:1,status:302,redirect:http://www.modsecurity.org"
';
}
}
}
}
EOF
$t->write_file("/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1');
$t->write_file("/subfolder1/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1/subfolder2');
$t->write_file("/subfolder1/subfolder2/index.html", "should be moved/blocked before this.");
$t->run();
$t->plan(9);
###############################################################################
# Performing requests at root
like(http_get('/index.html?what=root'), qr/^HTTP.*302/, 'redirect 302 - root');
like(http_get('/index.html?what=subfolder1'), qr/should be moved\/blocked before this./, 'nothing - requested subfolder1 at root');
like(http_get('/index.html?what=subfolder2'), qr/should be moved\/blocked before this./, 'nothing - requested subfolder2 at root');
# Performing requests at subfolder1
like(http_get('/subfolder1/index.html?what=root'), qr/should be moved\/blocked before this./, 'nothing - requested root at subfolder 1');
like(http_get('/subfolder1/index.html?what=subfolder1'), qr/^HTTP.*302/, 'redirect 302 - subfolder 1');
like(http_get('/subfolder1/index.html?what=subfolder2'), qr/should be moved\/blocked before this./, 'nothing - requested subfolder2 at subfolder1');
# Performing requests at subfolder2
like(http_get('/subfolder1/subfolder2/index.html?what=root'), qr/should be moved\/blocked before this./, 'nothing - requested root at subfolder 2');
like(http_get('/subfolder1/subfolder2/index.html?what=subfolder1'), qr/^HTTP.*302/, 'redirect 302 - subfolder 2');
like(http_get('/subfolder1/subfolder2/index.html?what=subfolder2'), qr/^HTTP.*302/, 'redirect 302 - subfolder 2');

View file

@ -1,205 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity module (HTTP/2).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
use Test::Nginx::HTTP2;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http http_v2/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080 http2;
server_name localhost;
location / {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
}
}
}
EOF
$t->write_file("/phase1", "should be moved/blocked before this.");
$t->write_file("/phase2", "should be moved/blocked before this.");
$t->write_file("/phase3", "should be moved/blocked before this.");
$t->write_file("/phase4", "should not be moved/blocked, headers delivered before phase 4.");
$t->run();
$t->plan(20);
###############################################################################
my ($phase, $s, $sid, $frames, $frame);
# Redirect (302)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect302" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 302, "redirect 302 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect302' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 302 - phase 4');
}
# Redirect (301)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect301" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 301, "redirect 301 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect301' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 301 - phase 4');
}
# Block (401)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block401" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 401, "block 401 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block401' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 401 - phase 4');
}
# Block (403)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block403" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "block 403 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block403' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 403 - phase 4');
}
# Nothing to detect
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=nothing" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame->{data}, "should be moved\/blocked before this.", "nothing phase ${phase}");
}
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase4?what=nothing" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame->{data}, "should not be moved\/blocked, headers delivered before phase 4.", 'nothing phase 4');

View file

@ -1,287 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity over the http proxy module (HTTP/2).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
use Test::Nginx::HTTP2;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http http_v2 proxy/)->plan(23);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080 http2;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
}
}
EOF
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
###############################################################################
my ($phase, $s, $sid, $frames, $frame);
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/SEE-THIS/, "proxy request");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/multi' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/AND-THIS/, "proxy request with multiple packets");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/', method => 'HEAD' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
unlike($frame->{data}, qr/SEE-THIS/, "proxy head request");
# Redirect (302)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect302" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 302, "redirect 302 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect302' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 302 - phase 4');
}
# Redirect (301)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect301" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 301, "redirect 301 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect301' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 301 - phase 4');
}
# Block (401)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block401" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 401, "block 401 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block401' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 401 - phase 4');
}
# Block (403)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block403" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "block 403 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block403' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 403 - phase 4');
}
# Nothing to detect
#like(http_get('/phase1?what=nothing'), qr/phase1\?what=nothing\' not found/, 'nothing phase 1');
#like(http_get('/phase2?what=nothing'), qr/phase2\?what=nothing\' not found/, 'nothing phase 2');
#like(http_get('/phase3?what=nothing'), qr/phase3\?what=nothing\' not found/, 'nothing phase 3');
#like(http_get('/phase4?what=nothing'), qr/phase4\?what=nothing\' not found/, 'nothing phase 4');
for $phase (1 .. 4) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=nothing" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/phase${phase}\?what=nothing\' not found/, "nothing phase ${phase}");
}
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
if ($uri eq '/') {
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
} elsif ($uri eq '/multi') {
print $client <<"EOF";
HTTP/1.1 200 OK
Connection: close
TEST-OK-IF-YOU-SEE-THIS
EOF
select undef, undef, undef, 0.1;
print $client 'AND-THIS';
} else {
print $client <<"EOF";
HTTP/1.1 404 Not Found
Connection: close
Oops, '$uri' not found
EOF
}
close $client;
}
}
###############################################################################

View file

@ -1,208 +0,0 @@
#!/usr/bin/perl
# Tests for ModSecurity over the http proxy module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http proxy/)->plan(23);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
}
}
EOF
$t->todo_alerts();
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
###############################################################################
like(http_get('/'), qr/SEE-THIS/, 'proxy request');
like(http_get('/multi'), qr/AND-THIS/, 'proxy request with multiple packets');
unlike(http_head('/'), qr/SEE-THIS/, 'proxy head request');
# Redirect (302)
like(http_get('/phase1?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 1');
like(http_get('/phase2?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 2');
like(http_get('/phase3?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 3');
is(http_get('/phase4?what=redirect302'), '', 'redirect 302 - phase 4');
# Redirect (301)
like(http_get('/phase1?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 1');
like(http_get('/phase2?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 2');
like(http_get('/phase3?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 3');
is(http_get('/phase4?what=redirect301'), '', 'redirect 301 - phase 4');
# Block (401)
like(http_get('/phase1?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 1');
like(http_get('/phase2?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 2');
like(http_get('/phase3?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 3');
is(http_get('/phase4?what=block401'), '', 'block 401 - phase 4');
# Block (403)
like(http_get('/phase1?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 1');
like(http_get('/phase2?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 2');
like(http_get('/phase3?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 3');
is(http_get('/phase4?what=block403'), '', 'block 403 - phase 4');
# Nothing to detect
like(http_get('/phase1?what=nothing'), qr/phase1\?what=nothing\' not found/, 'nothing phase 1');
like(http_get('/phase2?what=nothing'), qr/phase2\?what=nothing\' not found/, 'nothing phase 2');
like(http_get('/phase3?what=nothing'), qr/phase3\?what=nothing\' not found/, 'nothing phase 3');
like(http_get('/phase4?what=nothing'), qr/phase4\?what=nothing\' not found/, 'nothing phase 4');
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
if ($uri eq '/') {
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
} elsif ($uri eq '/multi') {
print $client <<"EOF";
HTTP/1.1 200 OK
Connection: close
TEST-OK-IF-YOU-SEE-THIS
EOF
select undef, undef, undef, 0.1;
print $client 'AND-THIS';
} else {
print $client <<"EOF";
HTTP/1.1 404 Not Found
Connection: close
Oops, '$uri' not found
EOF
}
close $client;
}
}
###############################################################################

View file

@ -1,224 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (request body operations, HTTP/2).
###############################################################################
use warnings;
use strict;
use Test::More;
use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
use Test::Nginx::HTTP2;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http http_v2 proxy auth_request/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8081;
location / {
return 200 "TEST-OK-IF-YOU-SEE-THIS";
}
}
server {
listen 127.0.0.1:8080 http2;
server_name localhost;
modsecurity on;
client_header_buffer_size 1024;
location /bodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_BODY "@rx BAD BODY" "id:11,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location /nobodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess Off
SecRule REQUEST_BODY "@rx BAD BODY" "id:21,phase:request,deny,log,status:403"
SecRule ARGS_POST|ARGS_POST_NAMES "@rx BAD ARG" "id:22,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location /bodylimitreject {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:31,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location /bodylimitprocesspartial {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction ProcessPartial
SecRule REQUEST_BODY "@rx BAD BODY" "id:41,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location = /auth {
return 200;
}
location = /useauth {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
';
auth_request /auth;
proxy_pass http://127.0.0.1:8081;
}
}
}
EOF
$t->run();
$t->plan(36);
###############################################################################
my ($s, $sid, $frames, $frame);
foreach my $method (('GET', 'POST', 'PUT', 'DELETE')) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodyaccess', 'body_more' => 1 });
$s->h2_body('GOOD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body access on, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodyaccess', 'body_more' => 1 });
$s->h2_body('VERY BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "${method} request body access on, block");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/nobodyaccess', 'body_more' => 1 });
$s->h2_body('VERY BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body access off, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ 'body_more' => 1,
headers => [
{name => ':method', value => "${method}" },
{name => ':scheme', value => 'http' },
{name => ':path', value => '/nobodyaccess' },
{name => 'host', value => 'localhost' },
{name => 'content-type', value => 'application/x-www-form-urlencoded' }
] });
$s->h2_body('test=VERY BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body access off (ARGS_POST), pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitreject', 'body_more' => 1 });
$s->h2_body('BODY' x 32);
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body limit reject, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitreject', 'body_more' => 1 });
$s->h2_body('BODY' x 33);
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "${method} request body limit reject, block");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitprocesspartial', 'body_more' => 1 });
$s->h2_body('BODY' x 32 . 'BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body limit process partial, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitprocesspartial', 'body_more' => 1 });
$s->h2_body('BODY' x 30 . 'BAD BODY' x 32);
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "${method} request body limit process partial, block");
}
TODO: {
# https://github.com/SpiderLabs/ModSecurity-nginx/issues/163
# https://github.com/nginx/nginx/commit/6c89d752c8ab3a3cc0832927484808b68153f8c4
local $TODO = 'not yet' unless $t->has_version('1.19.3');
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body' => 'BODY' x 16 });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size < client_header_buffer_size)");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body' => 'BODY' x 257 });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size > client_header_buffer_size)");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body_more' => 1 });
$s->h2_body('BODY' x 15, { 'body_more' => 1 });
select undef, undef, undef, 0.1;
$s->h2_body('BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size < client_header_buffer_size), no preread");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body_more' => 1 });
$s->h2_body('BODY' x 256, { 'body_more' => 1 });
select undef, undef, undef, 0.1;
$s->h2_body('BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size > client_header_buffer_size), no preread");
}
###############################################################################

View file

@ -1,251 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (request body operations).
###############################################################################
use warnings;
use strict;
use Test::More;
use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http proxy auth_request/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
client_header_buffer_size 1024;
location /bodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_BODY "@rx BAD BODY" "id:11,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /nobodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess Off
SecRule REQUEST_BODY "@rx BAD BODY" "id:21,phase:request,deny,log,status:403"
SecRule ARGS_POST|ARGS_POST_NAMES "@rx BAD ARG" "id:22,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitreject {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:31,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitrejectserver {
modsecurity off;
proxy_pass http://127.0.0.1:%%PORT_8082%%;
}
location /bodylimitprocesspartial {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction ProcessPartial
SecRule REQUEST_BODY "@rx BAD BODY" "id:41,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location = /auth {
return 200;
}
location = /useauth {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
';
auth_request /auth;
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8082%%;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:31,phase:request,deny,log,status:403"
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
}
EOF
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
$t->plan(40);
###############################################################################
foreach my $method (('GET', 'POST', 'PUT', 'DELETE')) {
like(http_req_body($method, '/bodyaccess', 'GOOD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body access on, pass");
like(http_req_body($method, '/bodyaccess', 'VERY BAD BODY'), qr/^HTTP.*403/, "$method request body access on, block");
like(http_req_body($method, '/nobodyaccess', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body access off, pass");
like(http_req_body_postargs($method, '/nobodyaccess', 'BAD ARG'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body access off (ARGS_POST), pass");
like(http_req_body($method, '/bodylimitreject', 'BODY' x 32), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body limit reject, pass");
like(http_req_body($method, '/bodylimitreject', 'BODY' x 33), qr/^HTTP.*403/, "$method request body limit reject, block");
like(http_req_body($method, '/bodylimitprocesspartial', 'BODY' x 32 . 'BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body limit process partial, pass");
like(http_req_body($method, '/bodylimitprocesspartial', 'BODY' x 30 . 'BAD BODY' x 32), qr/^HTTP.*403/, "$method request body limit process partial, block");
}
like(http_req_body('POST', '/useauth', 'BODY' x 16), qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size < client_header_buffer_size)");
like(http_req_body('POST', '/useauth', 'BODY' x 257), qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size > client_header_buffer_size)");
like(
http(
'POST /useauth HTTP/1.0' . CRLF
. 'Content-Length: 1028' . CRLF . CRLF
. 'BODY' x 256,
sleep => 0.1,
body => 'BODY'
),
qr/TEST-OK-IF-YOU-SEE-THIS/,
'POST with auth_request (request size > client_header_buffer_size), no preread'
);
like(
http(
'POST /useauth HTTP/1.0' . CRLF
. 'Content-Length: 64' . CRLF . CRLF
. 'BODY' x 15,
sleep => 0.1,
body => 'BODY'
),
qr/TEST-OK-IF-YOU-SEE-THIS/,
'POST with auth_request (request size < client_header_buffer_size), no preread'
);
foreach my $method (('GET', 'POST', 'PUT', 'DELETE')) {
like(http_req_body($method, '/bodylimitrejectserver', 'BODY' x 33), qr/^HTTP.*403/, "$method request body limit reject, block (inherited SecRequestBodyLimit)");
}
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
close $client;
}
}
sub http_req_body {
my $method = shift;
my $uri = shift;
my $last = pop;
return http( join '', (map {
my $body = $_;
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Content-Length: " . (length $body) . CRLF . CRLF
. $body
} @_),
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Connection: close" . CRLF
. "Content-Length: " . (length $last) . CRLF . CRLF
. $last
);
}
sub http_req_body_postargs {
my $method = shift;
my $uri = shift;
my $last = pop;
return http( join '', (map {
my $body = $_;
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Content-Type: application/x-www-form-urlencoded" . CRLF
. "Content-Length: " . (length "test=" . $body) . CRLF . CRLF
. "test=" . $body
} @_),
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Connection: close" . CRLF
. "Content-Type: application/x-www-form-urlencoded" . CRLF
. "Content-Length: " . (length "test=" . $last) . CRLF . CRLF
. "test=" . $last
);
}
###############################################################################

View file

@ -1,69 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (response body operations).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
location /body1 {
default_type text/plain;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecResponseBodyLimit 128
SecRule RESPONSE_BODY "@rx BAD BODY" "id:11,phase:response,deny,log,status:403"
';
}
}
}
EOF
$t->write_file("/body1", "BAD BODY");
$t->run();
$t->todo_alerts();
$t->plan(1);
###############################################################################
TODO: {
local $TODO = 'not yet';
like(http_get('/body1'), qr/^HTTP.*403/, 'response body (block)');
}

View file

@ -1,79 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (scoring).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
location /absolute {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq badarg1" "id:11,phase:2,setvar:tx.score=1"
SecRule ARGS "@streq badarg2" "id:12,phase:2,setvar:tx.score=2"
SecRule TX:SCORE "@ge 2" "id:199,phase:request,deny,log,status:403"
';
}
location /iterative {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq badarg1" "id:21,phase:2,setvar:tx.score=+1"
SecRule ARGS "@streq badarg2" "id:22,phase:2,setvar:tx.score=+1"
SecRule ARGS "@streq badarg3" "id:23,phase:2,setvar:tx.score=+1"
SecRule TX:SCORE "@ge 3" "id:299,phase:request,deny,log,status:403"
';
}
}
}
EOF
$t->write_file("/absolute", "should be moved/blocked before this.");
$t->write_file("/iterative", "should be moved/blocked before this.");
$t->run();
$t->plan(5);
###############################################################################
like(http_get('/absolute?what=badarg1'), qr/should be moved\/blocked before this./, 'absolute scoring 1 (pass)');
like(http_get('/absolute?what=badarg2'), qr/^HTTP.*403/, 'absolute scoring 2 (block)');
like(http_get('/iterative?arg1=badarg1'), qr/should be moved\/blocked before this./, 'iterative scoring 1 (pass)');
like(http_get('/iterative?arg1=badarg1&arg2=badarg2'), qr/should be moved\/blocked before this./, 'iterative scoring 2 (pass)');
like(http_get('/iterative?arg1=badarg1&arg2=badarg2&arg3=badarg3'), qr/^HTTP.*403/, 'iterative scoring 3 (block)');

View file

@ -1,167 +0,0 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (modsecurity_transaction_id).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->plan(5)->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
modsecurity_transaction_id "tid-HTTP-DEFAULT-$request_id";
server {
listen 127.0.0.1:8080;
server_name server1;
location / {
error_log %%TESTDIR%%/e_s1l1.log info;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
}
server {
listen 127.0.0.1:8080;
server_name server2;
modsecurity_transaction_id "tid-SERVER-DEFAULT-$request_id";
location / {
error_log %%TESTDIR%%/e_s2l1.log info;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /specific {
error_log %%TESTDIR%%/e_s2l2.log info;
modsecurity on;
modsecurity_transaction_id "tid-LOCATION-SPECIFIC-$request_id";
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /debuglog {
modsecurity on;
modsecurity_transaction_id "tid-DEBUG-$request_id";
modsecurity_rules '
SecRuleEngine On
SecDebugLog %%TESTDIR%%/modsec_debug.log
SecDebugLogLevel 4
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /auditlog {
modsecurity on;
modsecurity_transaction_id "tid-AUDIT-$request_id";
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecAuditEngine On
SecAuditLogParts A
SecAuditLog %%TESTDIR%%/modsec_audit.log
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
}
}
EOF
$t->run();
###############################################################################
# charge limit_req
http(<<EOF);
GET /?what=block403 HTTP/1.0
Host: server1
EOF
isnt(lines($t, 'e_s1l1.log', 'unique_id "tid-HTTP-DEFAULT-'), 0, 'http default');
http(<<EOF);
GET /?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'e_s2l1.log', 'unique_id "tid-SERVER-DEFAULT-'), 0, 'server default');
http(<<EOF);
GET /specific/?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'e_s2l2.log', 'unique_id "tid-LOCATION-SPECIFIC-'), 0, 'location specific');
http(<<EOF);
GET /debuglog/?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'modsec_debug.log', 'tid-DEBUG-'), 0, 'libmodsecurity debug log');
http(<<EOF);
GET /auditlog/?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'modsec_audit.log', 'tid-AUDIT-'), 0, 'libmodsecurity audit log');
###############################################################################
sub lines {
my ($t, $file, $pattern) = @_;
my $path = $t->testdir() . '/' . $file;
open my $fh, '<', $path or return "$!";
my $value = map { $_ =~ /\Q$pattern\E/ } (<$fh>);
close $fh;
return $value;
}
###############################################################################

View file

@ -1,172 +0,0 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
}
location /early-block {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
SecAction "id:900101,phase:1,nolog,pass,t:none,setvar:tx.trigger_phase1=1"
SecAction "id:900103,phase:1,nolog,pass,t:none,setvar:tx.trigger_phase3=1"
SecAction "id:900105,phase:1,nolog,pass,t:none,setvar:tx.trigger_phase5=1"
SecRule TX:TRIGGER_PHASE1 "@eq 1" "id:901111,phase:1,t:none,deny,log"
SecRule REQUEST_BODY "@rx attack" "id:901121,phase:2,t:none,deny,log"
SecRule TX:TRIGGER_PHASE3 "@eq 1" "id:901131,phase:3,t:none,deny,log"
SecRule RESPONSE_BODY "@rx ok" "id:901141,phase:4,t:none,deny,log"
SecRule TX:TRIGGER_PHASE5 "@eq 1" "id:901151,phase:5,t:none,pass,log,msg:\'This is the phase 5.\'"
';
}
}
}
EOF
$t->write_file("/phase1", "should be moved/blocked before this.");
$t->write_file("/phase2", "should be moved/blocked before this.");
$t->write_file("/phase3", "should be moved/blocked before this.");
$t->write_file("/phase4", "should not be moved/blocked, headers delivered before phase 4.");
$t->write_file("/early-block", "should be moved/blocked before this.");
$t->run();
$t->todo_alerts();
$t->plan(21);
###############################################################################
# Redirect (302)
like(http_get('/phase1?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 1');
like(http_get('/phase2?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 2');
like(http_get('/phase3?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 3');
is(http_get('/phase4?what=redirect302'), '', 'redirect 302 - phase 4');
# Redirect (301)
like(http_get('/phase1?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 1');
like(http_get('/phase2?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 2');
like(http_get('/phase3?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 3');
is(http_get('/phase4?what=redirect301'), '', 'redirect 301 - phase 4');
# Block (401)
like(http_get('/phase1?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 1');
like(http_get('/phase2?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 2');
like(http_get('/phase3?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 3');
is(http_get('/phase4?what=block401'), '', 'block 401 - phase 4');
# Block (403)
like(http_get('/phase1?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 1');
like(http_get('/phase2?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 2');
like(http_get('/phase3?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 3');
is(http_get('/phase4?what=block403'), '', 'block 403 - phase 4');
# Nothing to detect
like(http_get('/phase1?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 1');
like(http_get('/phase2?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 2');
like(http_get('/phase3?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 3');
like(http_get('/phase4?what=nothing'), qr/should not be moved\/blocked, headers delivered before phase 4./, 'nothing phase 4');
# early block (https://github.com/SpiderLabs/ModSecurity-nginx/issues/238)
like(http_get('/early-block'), qr/^HTTP.*403/, 'early block 403 (https://github.com/SpiderLabs/ModSecurity-nginx/issues/238)');

View file

@ -1,39 +0,0 @@
#!/usr/bin/perl
#
# Script to adjust nginx tests to include ModSecurity directives. It enables
# us to passively test nginx functionality with ModSecurity module enabled.
#
# sh command line variations:
#
# for i in *.t; do cp -n $i $i.orig; perl nginx-tests-cvt.pl < $i.orig > $i; done
# for i in *.t; do perl nginx-tests-cvt.pl < $i.orig > $i; done
# for i in *.t; do cp $i.orig $i; done
my $ignore = 0;
while (<STDIN>) {
print $_;
$ignore = 1 if (/^mail {/); # skip mail_*.t mail blocks
$ignore = 0 if (/^http {/);
next if ($ignore);
if (/^ *server_name .*;$/) {
next if (/^ *server_name *below;/); # skip duplication on refresh.t
next if (/^ *server_name *many4.example.com;/); # skip duplication on http_server_name.t
print "
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDebugLogLevel 9
SecRule ARGS \"\@streq whee\" \"id:10,phase:2\"
SecRule ARGS \"\@streq whee\" \"id:11,phase:2\"
';
";
}
}