mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
Redo build system to properly use autotools and avoid compilation with apxs util.
This commit is contained in:
531
tests/regression/action/00-disruptive-actions.t
Normal file
531
tests/regression/action/00-disruptive-actions.t
Normal file
@@ -0,0 +1,531 @@
|
||||
### Tests all of the actions in each phase
|
||||
|
||||
# Pass
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,pass"
|
||||
SecAction "phase:1,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,pass"
|
||||
SecAction "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:3,pass"
|
||||
SecAction "phase:3,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:4,pass"
|
||||
SecAction "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Allow
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,allow"
|
||||
SecAction "phase:1,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access allowed \(phase 1\). Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,allow"
|
||||
SecAction "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access allowed \(phase 2\). Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:3,allow"
|
||||
SecAction "phase:3,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access allowed \(phase 3\). Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:4,allow"
|
||||
SecAction "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access allowed \(phase 4\). Unconditional match in SecAction/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Deny
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 1\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 2\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:3,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 3\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 4\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Drop
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,drop"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with connection close \(phase 1\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,drop"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with connection close \(phase 2\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:3,drop"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with connection close \(phase 3\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:4,drop"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with connection close \(phase 4\). Unconditional match in SecAction./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Redirect
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:1 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 1\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:2 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 2\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:3 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 3\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:4 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with redirection to .* using status 302 \(phase 4\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Proxy
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:1 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied using proxy to \(phase 1\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:2 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied using proxy to \(phase 2\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:3 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 500 \(phase 3\) \(Configuration Error: Proxy action requested but it does not work in output phases\)./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:4 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 500 \(phase 4\) \(Configuration Error: Proxy action requested but it does not work in output phases\)./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
8
tests/regression/action/00-meta.t
Normal file
8
tests/regression/action/00-meta.t
Normal file
@@ -0,0 +1,8 @@
|
||||
### Test meta actions
|
||||
|
||||
# TODO: id
|
||||
# TODO: logdata
|
||||
# TODO: msg
|
||||
# TODO: rev
|
||||
# TODO: severity
|
||||
# TODO: tag
|
22
tests/regression/action/00-misc.t
Normal file
22
tests/regression/action/00-misc.t
Normal file
@@ -0,0 +1,22 @@
|
||||
### Test misc actions
|
||||
|
||||
# TODO: block
|
||||
# TODO: capture
|
||||
# TODO: chain
|
||||
# TODO: deprecatevar
|
||||
# TODO: exec
|
||||
# TODO: expirevar
|
||||
# TODO: initcol
|
||||
# TODO: multiMatch
|
||||
# TODO: pause
|
||||
# TODO: sanitiseArg
|
||||
# TODO: sanitiseMatched
|
||||
# TODO: sanitiseRequestHeader
|
||||
# TODO: sanitiseResponseHeader
|
||||
# TODO: setuid
|
||||
# TODO: setsid
|
||||
# TODO: setenv
|
||||
# TODO: setvar
|
||||
# TODO: skip
|
||||
# TODO: skipAfter
|
||||
# TODO: xmlns
|
8
tests/regression/action/00-transformations.t
Normal file
8
tests/regression/action/00-transformations.t
Normal file
@@ -0,0 +1,8 @@
|
||||
### Transformation tests
|
||||
|
||||
# NOTE: individual tests done in unit tests
|
||||
|
||||
# TODO: t:none to override default
|
||||
# TODO: t:none inline
|
||||
# TODO: combined
|
||||
# TODO: caching
|
49
tests/regression/action/10-append-prepend.t
Normal file
49
tests/regression/action/10-append-prepend.t
Normal file
@@ -0,0 +1,49 @@
|
||||
# TODO: Need more tests here
|
||||
|
||||
### append
|
||||
{
|
||||
type => "action",
|
||||
comment => "append content",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecContentInjection On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAction "phase:1,setvar:tx.test=test"
|
||||
SecAction "phase:2,append:'APPEND: \%{tx.test}'"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ "Added content to bottom: APPEND: test", 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/APPEND: test$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
### prepend
|
||||
{
|
||||
type => "action",
|
||||
comment => "prepend content",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecContentInjection On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAction "phase:1,setvar:tx.test=test"
|
||||
SecAction "phase:2,prepend:'PREPEND: \%{tx.test}'"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ "Added content to top: PREPEND: test", 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^PREPEND: test/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
56
tests/regression/action/10-ctl.t
Normal file
56
tests/regression/action/10-ctl.t
Normal file
@@ -0,0 +1,56 @@
|
||||
### ctl
|
||||
|
||||
### ruleRemoveById
|
||||
{
|
||||
type => "action",
|
||||
comment => "ruleRemoveById existing rule across phases",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecAction "phase:2,id:666,deny"
|
||||
SecAction "phase:1,pass,ctl:ruleRemoveById=666"
|
||||
),
|
||||
match_log => {
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "ruleRemoveById future rule across phases",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecAction "phase:1,pass,ctl:ruleRemoveById=666"
|
||||
SecAction "phase:2,id:666,deny"
|
||||
),
|
||||
match_log => {
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "ruleRemoveById future rule same phase",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecAction "phase:1,pass,ctl:ruleRemoveById=666"
|
||||
SecAction "phase:1,id:666,deny"
|
||||
),
|
||||
match_log => {
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
|
545
tests/regression/action/10-detectiononly-actions.t
Normal file
545
tests/regression/action/10-detectiononly-actions.t
Normal file
@@ -0,0 +1,545 @@
|
||||
### Tests all of the actions in each phase in detection only mode
|
||||
|
||||
# Pass
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAction "phase:1,pass,msg:'PASSED'"
|
||||
SecAction "phase:1,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,pass,msg:'PASSED'"
|
||||
SecAction "phase:2,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:3,pass,msg:'PASSED'"
|
||||
SecAction "phase:3,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "pass in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecAction "phase:4,pass,msg:'PASSED'"
|
||||
SecAction "phase:4,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*PASSED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Allow
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,allow,msg:'ALLOWED'"
|
||||
SecAction "phase:1,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ],
|
||||
-error => [ qr/Access allowed/, 1 ],
|
||||
# TODO: Allow should probably stop rule execution
|
||||
# -error => [ qr/DENIED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,allow,msg:'ALLOWED'"
|
||||
SecAction "phase:2,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ],
|
||||
-error => [ qr/Access allowed/, 1 ],
|
||||
# TODO: Allow should probably stop rule execution
|
||||
# -error => [ qr/DENIED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:3,allow,msg:'ALLOWED'"
|
||||
SecAction "phase:3,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ],
|
||||
-error => [ qr/Access allowed/, 1 ],
|
||||
# TODO: Allow should probably stop rule execution
|
||||
# -error => [ qr/DENIED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "allow in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:4,allow,msg:'ALLOWED'"
|
||||
SecAction "phase:4,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*ALLOWED/, 1 ],
|
||||
-error => [ qr/Access allowed/, 1 ],
|
||||
# TODO: Allow should probably stop rule execution
|
||||
# -error => [ qr/DENIED/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Deny
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:3,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "deny in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:4,deny,msg:'DENIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DENIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Drop
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:1",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:1,drop,msg:'DROPPED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:2",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:2,drop,msg:'DROPPED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:3",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:3,drop,msg:'DROPPED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "drop in phase:4",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecAction "phase:4,drop,msg:'DROPPED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction.*DROPPED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Redirect
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:1 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST 2$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:2 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST 2$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:3 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST 2$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "redirect in phase:4 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,redirect:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'REDIRECTED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*REDIRECTED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST 2$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# Proxy
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:1 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST 2$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:2 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:2,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
content => qr/^TEST 2$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:3 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:3,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "proxy in phase:4 (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 4
|
||||
SecRule REQUEST_URI "\@streq /test2.txt" "phase:4,proxy:'http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',msg:'PROXIED'"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. String match "\/test2.txt" at REQUEST_URI.*PROXIED/, 1 ],
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt",
|
||||
),
|
||||
},
|
564
tests/regression/action/10-logging.t
Normal file
564
tests/regression/action/10-logging.t
Normal file
@@ -0,0 +1,564 @@
|
||||
### Logging tests
|
||||
|
||||
# log/nolog (pass)
|
||||
{
|
||||
type => "action",
|
||||
comment => "log (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,log"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "nolog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# log/nolog (deny)
|
||||
{
|
||||
type => "action",
|
||||
comment => "log (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,log"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "nolog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# auditlog/noauditlog (pass)
|
||||
{
|
||||
type => "action",
|
||||
comment => "auditlog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "noauditlog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,noauditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# auditlog/noauditlog (deny)
|
||||
{
|
||||
type => "action",
|
||||
comment => "auditlog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "noauditlog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,noauditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# All log/nolog auditlog/noauditlog combos (pass)
|
||||
{
|
||||
type => "action",
|
||||
comment => "log,auditlog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "log,noauditlog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,log,noauditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "nolog,auditlog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,nolog,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/-H--\s+Message: .*Stopwatch: /s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "nolog,noauditlog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,nolog,noauditlog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "auditlog,log (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,auditlog,log"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "auditlog,nolog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,auditlog,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "noauditlog,log (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,noauditlog,log"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "noauditlog,nolog (pass)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,pass,noauditlog,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# All log/nolog auditlog/noauditlog combos (deny)
|
||||
{
|
||||
type => "action",
|
||||
comment => "log,auditlog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "log,noauditlog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,log,noauditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "nolog,auditlog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,nolog,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/-H--\s+Message: .*Stopwatch: /s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "nolog,noauditlog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,nolog,noauditlog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "auditlog,log (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,auditlog,log"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/Message: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "auditlog,nolog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,auditlog,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "noauditlog,log (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,noauditlog,log"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 1\)\. Unconditional match in SecAction\./, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "action",
|
||||
comment => "noauditlog,nolog (deny)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecAuditLogRelevantStatus xxx
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAction "phase:1,deny,status:403,noauditlog,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
23
tests/regression/config/00-load-modsec.t
Normal file
23
tests/regression/config/00-load-modsec.t
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
type => "config",
|
||||
comment => "module loaded",
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity for Apache.* configured\./, 10 ],
|
||||
},
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "minimal config",
|
||||
conf => sub {
|
||||
# Open the minimal conf file, substituting the
|
||||
# relative log paths with full paths.
|
||||
open(C, "<$ENV{DIST_ROOT}/modsecurity.conf-minimal") or die "$!\n";
|
||||
(my $conf = join('', <C>)) =~ s#Log logs/#Log $ENV{TEST_SERVER_ROOT}/logs/#g;
|
||||
close C;
|
||||
|
||||
return $conf;
|
||||
},
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity for Apache.* configured\./, 10 ],
|
||||
},
|
||||
},
|
264
tests/regression/config/10-audit-directives.t
Normal file
264
tests/regression/config/10-audit-directives.t
Normal file
@@ -0,0 +1,264 @@
|
||||
### SecAudit* directive tests
|
||||
|
||||
# SecAuditEngine
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditEngine On",
|
||||
conf => qq(
|
||||
SecAuditEngine On
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditEngine Off",
|
||||
conf => qq(
|
||||
SecAuditEngine Off
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
),
|
||||
match_log => {
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditEngine RelevantOnly (pos)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecResponseBodyAccess On
|
||||
SecDefaultAction "phase:2,log,auditlog,pass"
|
||||
SecRule REQUEST_URI "." "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditEngine RelevantOnly (neg)",
|
||||
conf => qq(
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecResponseBodyAccess On
|
||||
SecDefaultAction "phase:2,log,auditlog,pass"
|
||||
),
|
||||
match_log => {
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecAuditLogType & SecAuditLogStorageDir
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogType Serial",
|
||||
conf => qq(
|
||||
SecAuditEngine On
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecAuditLogType Serial
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^404$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/bogus",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogType Concurrent",
|
||||
conf => qq(
|
||||
SecAuditEngine On
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecAuditLogType Concurrent
|
||||
SecAuditLogStorageDir "$ENV{LOGS_DIR}/audit"
|
||||
),
|
||||
test => sub {
|
||||
### Perl code to parse the audit log entry and verify
|
||||
### that the concurrent audit log exists and contains
|
||||
### the correct data.
|
||||
###
|
||||
### TODO: Need some API for this :)
|
||||
###
|
||||
|
||||
# Parse log
|
||||
my $alogre = qr/^(?:\S+)\ (?:\S+)\ (?:\S+)\ (?:\S+)\ \[(?:[^:]+):(?:\d+:\d+:\d+)\ (?:[^\]]+)\]\ \"(?:.*)\"\ (?:\d+)\ (?:\S+)\ \"(?:.*)\"\ \"(?:.*)\"\ (\S+)\ \"(?:.*)\"\ (\S+)\ (?:\d+)\ (?:\d+)\ (?:\S+)(?:.*)$/m;
|
||||
my $alog = match_log("audit", $alogre, 1);
|
||||
chomp $alog;
|
||||
my @log = ($alog =~ m/$alogre/);
|
||||
my($id, $fn) = ($log[0], $log[1]);
|
||||
if (!$id or !$fn) {
|
||||
dbg("LOG ENTRY: $alog");
|
||||
die "Failed to parse audit log: $ENV{AUDIT_LOG}\n";
|
||||
}
|
||||
|
||||
# Verify concurrent log exists
|
||||
my $alogdatafn = "$ENV{LOGS_DIR}/audit$fn";
|
||||
if (! -e "$alogdatafn") {
|
||||
die "Audit log does not exist: $alogdatafn\n";
|
||||
}
|
||||
|
||||
# Verify concurrent log contents
|
||||
if (defined match_file($alogdatafn, qr/^--[^-]+-A--.*$id.*-Z--$/s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Error
|
||||
dbg("LOGDATA: \"$FILE{$alogdatafn}{buf}\"");
|
||||
die "Audit log data did not match.\n";
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecAuditLogRelevantStatus
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogRelevantStatus (pos)",
|
||||
conf => qq(
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecAuditLogRelevantStatus "^4"
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^404$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/bogus",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogRelevantStatus (neg)",
|
||||
conf => qq(
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecAuditLogRelevantStatus "^4"
|
||||
),
|
||||
match_log => {
|
||||
-audit => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecAuditLogParts
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogParts (minimal)",
|
||||
conf => qq(
|
||||
SecAuditEngine On
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecAuditLogParts "AZ"
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/-A--.*-Z--/s, 1 ],
|
||||
-audit => [ qr/-[B-Y]--/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1r&=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogParts (default)",
|
||||
conf => qq(
|
||||
SecAuditEngine On
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/-A--.*-B--.*-F--.*-H--.*-Z--/s, 1 ],
|
||||
-audit => [ qr/-[DEGIJK]--/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1r&=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecAuditLogParts (all)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecAuditEngine On
|
||||
SecAuditLog $ENV{AUDIT_LOG}
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecAuditLogParts "ABCDEFGHIJKZ"
|
||||
SecAction "phase:4,log,auditlog,allow"
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/-A--.*-B--.*-C--.*-F--.*-E--.*-H--.*-K--.*-Z--/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1r&=2",
|
||||
),
|
||||
},
|
278
tests/regression/config/10-debug-directives.t
Normal file
278
tests/regression/config/10-debug-directives.t
Normal file
@@ -0,0 +1,278 @@
|
||||
### SecDebug* directive tests
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLog (pos)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLog (neg)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 0",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 0
|
||||
SecRule REQUEST_URI "." "phase:1,deny"
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 1",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 1
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[[1]\] /, 1 ],
|
||||
-debug => [ qr/\]\[[2-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 2",
|
||||
conf => qq(
|
||||
SecRuleEngine DetectionOnly
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 2
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[2\] /, 1 ],
|
||||
-debug => [ qr/\]\[[3-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 3",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 3
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[3\] /, 1 ],
|
||||
-debug => [ qr/\]\[[4-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 4",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 4
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[4\] /, 1 ],
|
||||
-debug => [ qr/\]\[[5-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 5",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 5
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[5\] /, 1 ],
|
||||
-debug => [ qr/\]\[[6-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 6",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 6
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[6\] /, 1 ],
|
||||
-debug => [ qr/\]\[[7-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 7",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 7
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[7\] /, 1 ],
|
||||
-debug => [ qr/\]\[[8-9]\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 8",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 8
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[8\] /, 1 ],
|
||||
-debug => [ qr/\]\[9\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDebugLogLevel 9",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRuleScript "test.lua" "phase:1"
|
||||
SecRule REQUEST_URI "(.)" "phase:4,deny,deprecatevar:bogus"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/\]\[9\] /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
148
tests/regression/config/10-misc-directives.t
Normal file
148
tests/regression/config/10-misc-directives.t
Normal file
@@ -0,0 +1,148 @@
|
||||
### Misc directive tests
|
||||
|
||||
### TODO:
|
||||
# SecTmpDir
|
||||
# SecUploadKeepFiles
|
||||
# SecChrootDir
|
||||
# SecGuardianLog
|
||||
|
||||
# SecDefaultAction
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDefaultAction",
|
||||
conf => qq(
|
||||
SecRuleEngine on
|
||||
SecDefaultAction "phase:1,deny,status:500"
|
||||
SecRule REQUEST_URI "test.txt"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 500 \(phase 1\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecServerSignature
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecServerSignature On",
|
||||
conf => qq(
|
||||
SecServerSignature "NewServerSignature"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/NewServerSignature/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
raw => qr/^Server: +NewServerSignature$/m,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecDataDir
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecDataDir",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDataDir "$ENV{DATA_DIR}"
|
||||
SecAction initcol:ip=%{REMOTE_ADDR},setvar:ip.dummy=1,pass
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_file => {
|
||||
"$ENV{DATA_DIR}/ip.pag" => qr/\x00\x06dummy\x00\x00\x021\x00/,
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecTmpDir/SecUploadDir/SecUploadKeepFiles
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecTmpDir/SecUploadDir/SecUploadKeepFiles",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 4
|
||||
SecTmpDir "$ENV{TEMP_DIR}"
|
||||
SecUploadKeepFiles On
|
||||
SecUploadDir "$ENV{UPLOAD_DIR}"
|
||||
),
|
||||
test => sub {
|
||||
# Get the filename and make sure the file exists
|
||||
my $fn = match_log(debug => qr/Moved file from .* to ".*"\./, 5);
|
||||
die "Failed to determine uploaded filename\n" unless (defined $fn);
|
||||
|
||||
$fn =~ s/Moved file from .* to "(.*)"\..*/$1/;
|
||||
die "File does not exist: $fn\n" unless (-e $fn);
|
||||
|
||||
# Check the contents of the file
|
||||
return 0 if (match_file($fn, qr/^TESTFILE$/m));
|
||||
|
||||
msg("Failed to match contents of uploaded file: $fn");
|
||||
return 1;
|
||||
},
|
||||
match_log => {
|
||||
debug => [ qr/Created temporary file.*$ENV{TEMP_DIR}/, 1 ],
|
||||
-debug => [ qr/Failed to /, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------19813181771830765643996187206",
|
||||
],
|
||||
q(-----------------------------19813181771830765643996187206
|
||||
Content-Disposition: form-data; name="upload-file"; filename="test"
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
TESTFILE
|
||||
-----------------------------19813181771830765643996187206
|
||||
Content-Disposition: form-data; name="file"
|
||||
|
||||
Upload File
|
||||
-----------------------------19813181771830765643996187206--),
|
||||
),
|
||||
},
|
||||
|
||||
# SecWebAppId
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecWebAppId",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 4
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAuditEngine RelevantOnly
|
||||
SecWebAppId "app-1"
|
||||
SecAction "pass,log,auditlog,id:1"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
debug => [ qr/Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
audit => [ qr/^WebApp-Info: "app-1"/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
548
tests/regression/config/10-request-directives.t
Normal file
548
tests/regression/config/10-request-directives.t
Normal file
@@ -0,0 +1,548 @@
|
||||
### Tests for directives altering how a request is handled
|
||||
|
||||
# SecArgumentSeparator
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecArgumentSeparator (get-pos)",
|
||||
conf => q(
|
||||
SecRuleEngine On
|
||||
SecArgumentSeparator ";"
|
||||
SecRule ARGS:a "@streq 1" "phase:1,deny,chain"
|
||||
SecRule ARGS:b "@streq 2"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 1\)\. String match "2" at ARGS:b\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?a=1;b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecArgumentSeparator (get-neg)",
|
||||
conf => q(
|
||||
SecRuleEngine On
|
||||
SecRule ARGS:a "@streq 1" "phase:1,deny,chain"
|
||||
SecRule ARGS:b "@streq 2"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?a=1;b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecArgumentSeparator (post-pos)",
|
||||
conf => q(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecArgumentSeparator ";"
|
||||
SecRule ARGS:a "@streq 1" "phase:2,deny,chain"
|
||||
SecRule ARGS:b "@streq 2"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 2\)\. String match "2" at ARGS:b\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1;b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecArgumentSeparator (post-neg)",
|
||||
conf => q(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRule ARGS:a "@streq 1" "phase:2,deny"
|
||||
SecRule ARGS:b "@streq 2" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1;b=2",
|
||||
),
|
||||
},
|
||||
|
||||
# SecRequestBodyAccess
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyAccess (pos)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRule ARGS:a "\@streq 1" "phase:2,deny,chain"
|
||||
SecRule ARGS:b "\@streq 2"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 2\)\. String match "2" at ARGS:b\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyAccess (neg)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess Off
|
||||
SecRule ARGS:a "\@streq 1" "phase:2,deny"
|
||||
SecRule ARGS:b "\@streq 2" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
|
||||
# SecRequestBodyLimit
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (equal)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 7
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Request body is larger than the configured limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (greater)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 5
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Request body .*is larger than the configured limit \(5\)\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^413$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (equal - chunked)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 276
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Request body is larger than the configured limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (greater - chunked)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 256
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Request body .*is larger than the configured limit \(256\)\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^413$/,
|
||||
},
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (ctl:ruleEngine=off)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 5
|
||||
|
||||
SecAction "phase:1,pass,nolog,ctl:ruleEngine=off"
|
||||
SecRule REQUEST_BODY "." "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Request body .*is larger than the configured limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (ctl:requestBodyAccess=off)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 5
|
||||
|
||||
SecAction "phase:1,pass,nolog,ctl:requestBodyAccess=off"
|
||||
SecRule REQUEST_BODY "." "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Request body .*is larger than the configured limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"a=1&b=2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (ctl:ruleEngine=off - chunked)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 256
|
||||
|
||||
SecAction "phase:1,pass,nolog,ctl:ruleEngine=off"
|
||||
SecRule REQUEST_BODY "." "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Request body .*is larger than the configured limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyLimit (ctl:requestBodyAccess=off - chunked)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 256
|
||||
|
||||
SecAction "phase:1,pass,nolog,ctl:requestBodyAccess=off"
|
||||
SecRule REQUEST_BODY "." "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Request body .*is larger than the configured limit \(256\)\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
|
||||
# SecRequestBodyInMemoryLimit
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyInMemoryLimit (equal)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 1000
|
||||
SecRequestBodyInMemoryLimit 276
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/Input filter: Request too large to store in memory, switching to disk\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecRequestBodyInMemoryLimit (greater)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 1000
|
||||
SecRequestBodyInMemoryLimit 16
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Input filter: Request too large to store in memory, switching to disk\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
|
||||
# SecCookieFormat
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecCookieFormat (pos)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 5
|
||||
SecCookieFormat 1
|
||||
SecRule REQUEST_COOKIES_NAMES "\@streq SESSIONID" "phase:1,deny,chain"
|
||||
SecRule REQUEST_COOKIES:\$SESSIONID_PATH "\@streq /" "chain"
|
||||
SecRule REQUEST_COOKIES:SESSIONID "\@streq cookieval"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 1\)\. String match "cookieval" at REQUEST_COOKIES:SESSIONID\./, 1 ],
|
||||
debug => [ qr(Adding request cookie: name "\$SESSIONID_PATH", value "/"), 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Cookie" => q($Version="1"; SESSIONID="cookieval"; $PATH="/"),
|
||||
],
|
||||
undef,
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecCookieFormat (neg)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 5
|
||||
SecCookieFormat 0
|
||||
SecRule REQUEST_COOKIES_NAMES "\@streq SESSIONID" "phase:1,deny,chain"
|
||||
SecRule REQUEST_COOKIES:\$SESSIONID_PATH "\@streq /" "chain"
|
||||
SecRule REQUEST_COOKIES:SESSIONID "\@streq cookieval"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
-debug => [ qr(Adding request cookie: name "\$SESSIONID_PATH", value "/"), 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Cookie" => q($Version="1"; SESSIONID="cookieval"; $PATH="/"),
|
||||
],
|
||||
undef,
|
||||
),
|
||||
},
|
||||
|
174
tests/regression/config/10-response-directives.t
Normal file
174
tests/regression/config/10-response-directives.t
Normal file
@@ -0,0 +1,174 @@
|
||||
### Tests for directives altering how a response is handled
|
||||
|
||||
# SecResponseBodyMimeTypesClear
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyMimeTypesClear",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeTypesClear
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule RESPONSE_BODY "TEST" "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
debug => [ qr/Not buffering response body for unconfigured MIME type/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecResponseBodyAccess & SecResponseBodyMimeType
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyAccess On",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecRule RESPONSE_BODY "TEST" "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Access denied with code 403 \(phase 4\)\. Pattern match "TEST" at RESPONSE_BODY\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyAccess Off",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecResponseBodyAccess Off
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecRule RESPONSE_BODY "TEST" "phase:4,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Access denied/, 1 ],
|
||||
debug => [ qr/Response body buffering is not enabled\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecResponseBodyLimit
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyLimit (equal)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecResponseBodyLimit 8192
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Content-Length \(\d+\) over the limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyLimit (less)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecResponseBodyLimit 9000
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Content-Length \(\d+\) over the limit/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyLimit (greater)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecResponseBodyLimit 8000
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Content-Length \(\d+\) over the limit \(8000\)\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# ResponseBodyLimitAction
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyLimitAction Reject",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecResponseBodyLimit 5
|
||||
SecResponseBodyLimitAction Reject
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Content-Length \(\d+\) over the limit \(5\)\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^500$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
comment => "SecResponseBodyLimitAction ProcessPartial",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecResponseBodyLimit 5
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 4
|
||||
SecResponseBodyLimitAction ProcessPartial
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Content-Length \(\d+\) over the limit/, 1 ],
|
||||
debug => [ qr/Processing partial response body \(limit 5\)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/8k.txt",
|
||||
),
|
||||
},
|
35
tests/regression/config/20-chroot.t
Normal file
35
tests/regression/config/20-chroot.t
Normal file
@@ -0,0 +1,35 @@
|
||||
### SecChroot tests
|
||||
# TODO: Will not work as we need root access
|
||||
|
||||
#{
|
||||
# type => "config",
|
||||
# comment => "SecChroot",
|
||||
# httpd_opts => qw(
|
||||
# -DCHROOT
|
||||
# ),
|
||||
# conf => qq(
|
||||
# # These will be in the chroot
|
||||
# PidFile /logs/httpd.pid
|
||||
# ScoreBoardFile /logs/httpd.scoreboard
|
||||
# User nobody
|
||||
# Group nogroup
|
||||
#
|
||||
# SecAuditEngine On
|
||||
# SecDebugLog $ENV{DEBUG_LOG}
|
||||
# SecDebugLogLevel 9
|
||||
# SecAuditLog $ENV{AUDIT_LOG}
|
||||
# SecAuditLogStorageDir "/logs/audit"
|
||||
# SecAuditLogType Concurrent
|
||||
# SecChrootDir "$ENV{TEST_SERVER_ROOT}"
|
||||
# ),
|
||||
# match_log => {
|
||||
# debug => [ qr/./, 1 ],
|
||||
# audit => [ qr/./, 1 ],
|
||||
# },
|
||||
# match_response => {
|
||||
# status => qr/^200$/,
|
||||
# },
|
||||
# request => new HTTP::Request(
|
||||
# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
# ),
|
||||
#},
|
1815
tests/regression/misc/00-multipart-parser.t
Normal file
1815
tests/regression/misc/00-multipart-parser.t
Normal file
File diff suppressed because it is too large
Load Diff
151
tests/regression/misc/00-phases.t
Normal file
151
tests/regression/misc/00-phases.t
Normal file
@@ -0,0 +1,151 @@
|
||||
### Test the phases
|
||||
|
||||
# Phase 1 (request headers)
|
||||
{
|
||||
type => "misc",
|
||||
comment => "phase 1",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecRule REQUEST_LINE "^POST" "phase:1,pass,log,auditlog"
|
||||
SecRule ARGS "val1" "phase:1,pass,log,auditlog"
|
||||
SecRule RESPONSE_HEADERS:Last-Modified "." "phase:1,pass,log,auditlog"
|
||||
SecRule RESPONSE_BODY "TEST" "phase:1,pass,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "\^POST" at REQUEST_LINE/, 1 ],
|
||||
-error => [ qr/Pattern match .* (ARGS|RESPONSE)/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# Phase 2 (request body)
|
||||
{
|
||||
type => "misc",
|
||||
comment => "phase 2",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecRule REQUEST_LINE "^POST" "phase:2,pass,log,auditlog"
|
||||
SecRule ARGS "val1" "phase:2,pass,log,auditlog"
|
||||
SecRule RESPONSE_HEADERS:Last-Modified "." "phase:2,pass,log,auditlog"
|
||||
SecRule RESPONSE_BODY "TEST" "phase:2,pass,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS/s, 1 ],
|
||||
-error => [ qr/Pattern match .* RESPONSE/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# Phase 3 (response headers)
|
||||
{
|
||||
type => "misc",
|
||||
comment => "phase 3",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecRule REQUEST_LINE "^POST" "phase:3,pass,log,auditlog"
|
||||
SecRule ARGS "val1" "phase:3,pass,log,auditlog"
|
||||
SecRule RESPONSE_HEADERS:Last-Modified "." "phase:3,pass,log,auditlog"
|
||||
SecRule RESPONSE_BODY "TEST" "phase:3,pass,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS.*Pattern match "\." at RESPONSE_HEADERS/s, 1 ],
|
||||
-error => [ qr/Pattern match .* RESPONSE_BODY/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# Phase 4 (response body)
|
||||
{
|
||||
type => "misc",
|
||||
comment => "phase 4",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecDebugLog "$ENV{DEBUG_LOG}"
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_LINE "^POST" "phase:4,pass,log,auditlog"
|
||||
SecRule ARGS "val1" "phase:4,pass,log,auditlog"
|
||||
SecRule RESPONSE_HEADERS:Last-Modified "." "phase:4,pass,log,auditlog"
|
||||
SecRule RESPONSE_BODY "TEST" "phase:4,pass,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS.*Pattern match "\." at RESPONSE_HEADERS.*Pattern match "TEST" at RESPONSE_BODY/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# Phase 5 (logging)
|
||||
{
|
||||
type => "misc",
|
||||
comment => "phase 5",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType text/plain null
|
||||
SecRule REQUEST_LINE "^POST" "phase:5,pass,log,auditlog"
|
||||
SecRule ARGS "val1" "phase:5,pass,log,auditlog"
|
||||
SecRule RESPONSE_HEADERS:Last-Modified "." "phase:5,pass,log,auditlog"
|
||||
SecRule RESPONSE_BODY "TEST" "phase:5,pass,log,auditlog"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "\^POST" at REQUEST_LINE.*Pattern match "val1" at ARGS.*Pattern match "\." at RESPONSE_HEADERS.*Pattern match "TEST" at RESPONSE_BODY/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
38
tests/regression/misc/10-pcre.t
Normal file
38
tests/regression/misc/10-pcre.t
Normal file
File diff suppressed because one or more lines are too long
189
tests/regression/misc/10-tfn-cache.t
Normal file
189
tests/regression/misc/10-tfn-cache.t
Normal file
@@ -0,0 +1,189 @@
|
||||
### Transformation Caching
|
||||
|
||||
{
|
||||
type => "misc",
|
||||
comment => "tfncache (simple fully cached)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
|
||||
# We need to make this work no matter what the defaults may change to
|
||||
SecCacheTransformations On "minlen:1,maxlen:0"
|
||||
|
||||
# This should cache it
|
||||
SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
|
||||
# This should use the cached value
|
||||
SecRule ARGS_GET:test "foobar" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/removeWhiteSpace,lowercase: "foobar" .*cached/, 1 ],
|
||||
-debug => [ qr/partially cached/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Foo+Bar",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "tfncache (simple partially cached)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
|
||||
# We need to make this work no matter what the defaults may change to
|
||||
SecCacheTransformations On "minlen:1,maxlen:0,incremental:off,maxitems:0"
|
||||
|
||||
# This should cache it
|
||||
SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,pass,nolog"
|
||||
|
||||
# This should use the partially cached value
|
||||
SecRule ARGS_GET:test "foobar" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/removeWhiteSpace: "FooBar" .*partially cached/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Foo+Bar",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "tfncache (separate phases)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
|
||||
# We need to make this work no matter what the defaults may change to
|
||||
SecCacheTransformations On "minlen:1,maxlen:0"
|
||||
|
||||
# This should cache it
|
||||
SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
|
||||
# This should use the cached value
|
||||
SecRule ARGS_GET:test "foobar" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,deny"
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/removeWhiteSpace,lowercase: "foobar" .*cached/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Foo+Bar",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "tfncache (non-modifying tfns cached)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
|
||||
# We need to make this work no matter what the defaults may change to
|
||||
SecCacheTransformations On "minlen:1,maxlen:0"
|
||||
|
||||
# This should cache it
|
||||
SecRule ARGS_GET "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
|
||||
# This should use the cached value
|
||||
SecRule ARGS_GET:test "foobar" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/removeWhiteSpace,lowercase: "foobar" .*cached/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=foo+bar",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "tfncache (unique keys)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
|
||||
# We need to make this work no matter what the defaults may change to
|
||||
SecCacheTransformations On "minlen:1,maxlen:0"
|
||||
|
||||
# This should cache it
|
||||
SecRule ARGS "WillNotMatch" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,pass"
|
||||
|
||||
# This should see cached versions of *both* ARGS_GET
|
||||
SecRule ARGS:test "queryval" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,deny,chain"
|
||||
SecRule ARGS:test "firstval" "t:none,t:removeWhiteSpace,t:lowercase,chain"
|
||||
SecRule ARGS:test "secondval" "t:none,t:removeWhiteSpace,t:lowercase"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/removeWhiteSpace,lowercase: "queryval" .*removeWhiteSpace,lowercase: "firstval" .*cached.*removeWhiteSpace,lowercase: "secondval" .*cached/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?test=Query+Val",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
# Args
|
||||
"test=First+Val&test=Second+Val",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "tfncache (large cache)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
|
||||
<IfDefine MODSEC_2.5>
|
||||
SecRequestBodyNoFilesLimit 1048576
|
||||
</IfDefine>
|
||||
SecRequestBodyInMemoryLimit 131072
|
||||
SecResponseBodyLimit 1048576
|
||||
|
||||
# We need to make this work no matter what the defaults may change to
|
||||
SecCacheTransformations On "minlen:1,maxlen:0,maxitems:0"
|
||||
|
||||
# This should cache it in all phases
|
||||
SecRule ARGS "WillNotMatch" "phase:1,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
SecRule ARGS "WillNotMatch" "phase:2,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
SecRule ARGS "WillNotMatch" "phase:3,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
SecRule ARGS "WillNotMatch" "phase:4,t:none,t:removeWhiteSpace,t:lowercase,pass,nolog"
|
||||
|
||||
# This should use the cached value
|
||||
SecRule ARGS "foobar" "phase:4,t:none,t:removeWhiteSpace,t:lowercase,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Adding request argument \(BODY\): name "test", value "Foo Bar"/, 60, "Waiting for httpd to process request: "],
|
||||
-error => [ qr/segmentation fault/i, 60 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
# 1000 Args
|
||||
join("&", map { sprintf "arg%08d=0123456789abcdef+0123456789ABCDEF+0123456789abcdef", $_ } (1 .. 1000))."&test=Foo+Bar",
|
||||
),
|
||||
},
|
91
tests/regression/rule/00-basics.t
Normal file
91
tests/regression/rule/00-basics.t
Normal file
@@ -0,0 +1,91 @@
|
||||
### Tests for basic rule components
|
||||
|
||||
# SecAction
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecAction (override default)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 4
|
||||
SecAction "nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/Warning\. Unconditional match in SecAction\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecRule
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRule (no action)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 5
|
||||
SecDefaultAction "phase:2,deny,status:403"
|
||||
SecRule ARGS:test "value"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: /, 1 ],
|
||||
debug => [ qr/Rule [0-9a-f]+: SecRule "ARGS:test" "\@rx value" "phase:2,deny,status:403"$/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?test=value",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRule (action)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 5
|
||||
SecDefaultAction "phase:2,pass"
|
||||
SecRule ARGS:test "value" "deny,status:403"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: /, 1 ],
|
||||
debug => [ qr/Rule [0-9a-f]+: SecRule "ARGS:test" "\@rx value" "phase:2,deny,status:403"$/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?test=value",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRule (chain)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 5
|
||||
SecDefaultAction "phase:2,log,noauditlog,pass,tag:foo"
|
||||
SecRule ARGS:test "value" "chain,phase:2,deny,status:403"
|
||||
SecRule &ARGS "\@eq 1" "chain,setenv:tx.foo=bar"
|
||||
SecRule REQUEST_METHOD "\@streq GET"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: /, 1 ],
|
||||
debug => [ qr/Rule [0-9a-f]+: SecRule "ARGS:test" "\@rx value" "phase:2,log,noauditlog,tag:foo,chain,deny,status:403"\r?\n.*Rule [0-9a-f]+: SecRule "&ARGS" "\@eq 1" "chain,setenv:tx.foo=bar"\r?\n.*Rule [0-9a-f]+: SecRule "REQUEST_METHOD" "\@streq GET"\r?\n/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?test=value",
|
||||
),
|
||||
},
|
4
tests/regression/rule/00-inheritance.t
Normal file
4
tests/regression/rule/00-inheritance.t
Normal file
@@ -0,0 +1,4 @@
|
||||
### Tests for rule inheritance
|
||||
|
||||
### TODO:
|
||||
# SecRuleInheritance
|
63
tests/regression/rule/00-script.t
Normal file
63
tests/regression/rule/00-script.t
Normal file
@@ -0,0 +1,63 @@
|
||||
### Test for SecRuleScript
|
||||
|
||||
# Lua
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleScript (lua absolute nomatch)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 1
|
||||
SecRuleScript "$ENV{CONF_DIR}/test.lua" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Lua script matched\./, 1 ],
|
||||
debug => [ qr/Test message\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleScript (lua relative nomatch)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 1
|
||||
SecRuleScript "test.lua" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Lua script matched\./, 1 ],
|
||||
debug => [ qr/Test message\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleScript (lua relative match)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 1
|
||||
SecRuleScript "match.lua" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/ModSecurity: Access denied with code 403 \(phase 2\)\. Lua script matched\./, 1 ],
|
||||
debug => [ qr/Test message\./, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
419
tests/regression/rule/10-xml.t
Normal file
419
tests/regression/rule/10-xml.t
Normal file
@@ -0,0 +1,419 @@
|
||||
### Test for XML operator rules
|
||||
|
||||
### Validate Scheme
|
||||
# OK
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateSchema (validate ok)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Successfully validated payload against Schema/s, 1 ],
|
||||
-debug => [ qr/XML parser error|validation failed|Failed to load/, 1 ],
|
||||
-error => [ qr/XML parser error|validation failed|Failed to load/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:tns="http://www.bluebank.example.com/axis/getBalance.jws"
|
||||
xmlns:types="http://www.bluebank.example.com/axis/getBalance.jws/encodedTypes"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<q1:getInput xmlns:q1="http://DefaultNamespace">
|
||||
<id xsi:type="xsd:string">12123</id>
|
||||
</q1:getInput>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Failed attribute value
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateSchema (validate attribute value failed)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\
|
||||
"phase:2,deny,log,auditlog,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*'badval' is not a valid value of the local atomic type.*Schema validation failed/s, 1 ],
|
||||
-debug => [ qr/Successfully validated payload against Schema|\n\r?\n/, 1 ],
|
||||
audit => [ qr/^Message: Element.*'badval' is not a valid value of the local atomic type\.\nMessage:/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:tns="http://www.bluebank.example.com/axis/getBalance.jws"
|
||||
xmlns:types="http://www.bluebank.example.com/axis/getBalance.jws/encodedTypes"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<soap:Body soap:mustUnderstand="badval" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<q1:getInput xmlns:q1="http://DefaultNamespace">
|
||||
<id xsi:type="xsd:string">12123</id>
|
||||
</q1:getInput>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Failed validation
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateSchema (validate failed)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*element is not expected/s, 1 ],
|
||||
-debug => [ qr/XML parser error|Failed to load/, 1 ],
|
||||
-error => [ qr/XML parser error|Failed to load/, 1 ],
|
||||
audit => [ qr/^Message: Element.*This element is not expected.*\nMessage:/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:tns="http://www.bluebank.example.com/axis/getBalance.jws"
|
||||
xmlns:types="http://www.bluebank.example.com/axis/getBalance.jws/encodedTypes"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<soap:xBody soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<q1:getInput xmlns:q1="http://DefaultNamespace">
|
||||
<id xsi:type="xsd:string">12123</id>
|
||||
</q1:getInput>
|
||||
</soap:xBody>
|
||||
</soap:Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Bad XML
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateSchema (bad XML)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope.xsd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error.*validation failed because content is not well formed/s, 1 ],
|
||||
-debug => [ qr/Failed to load|Successfully validated/, 1 ],
|
||||
-error => [ qr/Failed to load|Successfully validated/, 1 ],
|
||||
audit => [ qr/^Message: .*Failed parsing document.*\nMessage:/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelop xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:tns="http://www.bluebank.example.com/axis/getBalance.jws"
|
||||
xmlns:types="http://www.bluebank.example.com/axis/getBalance.jws/encodedTypes"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<q1:getInput xmlns:q1="http://DefaultNamespace">
|
||||
<id xsi:type="xsd:string">12123</id>
|
||||
</q1:getInput>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Bad schema
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateSchema (bad schema)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateSchema $ENV{CONF_DIR}/SoapEnvelope-bad.xsd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Failed to parse the XML resource.*Failed to load Schema/s, 1 ],
|
||||
audit => [ qr/^Message: .*Failed to parse the XML resource.*\nMessage: Rule processing failed/m, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
||||
xmlns:tns="http://www.bluebank.example.com/axis/getBalance.jws"
|
||||
xmlns:types="http://www.bluebank.example.com/axis/getBalance.jws/encodedTypes"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<q1:getInput xmlns:q1="http://DefaultNamespace">
|
||||
<id xsi:type="xsd:string">12123</id>
|
||||
</q1:getInput>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
|
||||
# Validate DTD
|
||||
# OK
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateDTD (validate ok)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope.dtd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Successfully validated payload against DTD/s, 1 ],
|
||||
-debug => [ qr/XML parser error|validation failed|Failed to load/, 1 ],
|
||||
-error => [ qr/XML parser error|validation failed|Failed to load/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Envelope SYSTEM "SoapEnvelope.dtd">
|
||||
<Envelope>
|
||||
<Body>
|
||||
<getInput>
|
||||
<id type="string">12123</id>
|
||||
</getInput>
|
||||
</Body>
|
||||
</Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Failed validation
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateDTD (validate failed)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope.dtd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*content does not follow the DTD/s, 1 ],
|
||||
-debug => [ qr/XML parser error|Failed to load/, 1 ],
|
||||
-error => [ qr/XML parser error|Failed to load/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Envelope SYSTEM "SoapEnvelope.dtd">
|
||||
<Envelope>
|
||||
<xBody>
|
||||
<getInput>
|
||||
<id type="string">12123</id>
|
||||
</getInput>
|
||||
</xBody>
|
||||
</Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Bad XML
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateDTD (bad XML)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope.dtd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error.*validation failed because content is not well formed/s, 1 ],
|
||||
-debug => [ qr/Failed to load|Successfully validated/, 1 ],
|
||||
-error => [ qr/Failed to load|Successfully validated/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^403$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Envelope SYSTEM "SoapEnvelope.dtd">
|
||||
<Envelop>
|
||||
<Body>
|
||||
<getInput>
|
||||
<id type="string">12123</id>
|
||||
</getInput>
|
||||
</Body>
|
||||
</Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
# Bad DTD
|
||||
{
|
||||
type => "rule",
|
||||
comment => "validateDTD (bad DTD)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" \\
|
||||
"phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
|
||||
SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345
|
||||
SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope-bad.dtd" \\
|
||||
"phase:2,deny,id:12345"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 1\).*Target value: "\[XML document tree\]".*Failed to load DTD/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "text/xml",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Envelope SYSTEM "SoapEnvelope.dtd">
|
||||
<Envelope>
|
||||
<Body>
|
||||
<getInput>
|
||||
<id type="string">12123</id>
|
||||
</getInput>
|
||||
</Body>
|
||||
</Envelope>
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
176
tests/regression/rule/20-exceptions.t
Normal file
176
tests/regression/rule/20-exceptions.t
Normal file
@@ -0,0 +1,176 @@
|
||||
### Tests for rule exceptions
|
||||
|
||||
# SecRuleRemoveById
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleRemoveById (single)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1"
|
||||
SecRuleRemoveById 1
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleRemoveById (multiple)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:2"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:3"
|
||||
SecRuleRemoveById 1 2 3
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleRemoveById (range)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:2"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:3"
|
||||
SecRuleRemoveById 1-3
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleRemoveById (multiple + range)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:2"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:3"
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:4"
|
||||
SecRuleRemoveById 1 2-4
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecRuleRemoveByMsg
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleRemoveByMsg",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule'"
|
||||
SecRuleRemoveByMsg "testing rule"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/Starting phase REQUEST_HEADERS\..*This phase consists of 0 rule.*Starting phase RESPONSE_HEADERS\./s, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
|
||||
# SecRuleUpdateActionById
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleUpdateActionById",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule'"
|
||||
SecRuleUpdateActionById 1 "pass,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/id:1,.*,pass,nolog/, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "rule",
|
||||
comment => "SecRuleUpdateActionById (chain)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule REQUEST_URI "test" "phase:1,deny,status:500,id:1,msg:'testing rule',chain"
|
||||
SecRule ARGS "bar"
|
||||
SecRuleUpdateActionById 1 "pass,nolog"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
-audit => [ qr/./, 1 ],
|
||||
debug => [ qr/id:1,.*,pass,nolog/, 1 ],
|
||||
-debug => [ qr/Access denied/, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?foo=bar",
|
||||
),
|
||||
},
|
8
tests/regression/server_root/conf/SoapEnvelope-bad.dtd
Normal file
8
tests/regression/server_root/conf/SoapEnvelope-bad.dtd
Normal file
@@ -0,0 +1,8 @@
|
||||
<!-- A stupid Soap DTD example -->
|
||||
<!ELEMENT Envelope (Header?,Body)>
|
||||
<!ELEMENT Header (#PCDATA)>
|
||||
<!ELEMENT Body (getInput)>
|
||||
|
||||
<!ELEMENT getInput (id)>
|
||||
<!ELEMENT id (#PCDATA)>
|
||||
<!ATLIST id type CDATA #REQUIRED>
|
126
tests/regression/server_root/conf/SoapEnvelope-bad.xsd
Normal file
126
tests/regression/server_root/conf/SoapEnvelope-bad.xsd
Normal file
@@ -0,0 +1,126 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
|
||||
<!-- Schema for the SOAP/1.1 envelope
|
||||
|
||||
Portions © 2001 DevelopMentor.
|
||||
© 2001 W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved.
|
||||
|
||||
This document is governed by the W3C Software License [1] as described in the FAQ [2].
|
||||
[1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
|
||||
[2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
|
||||
By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make:
|
||||
|
||||
1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
|
||||
|
||||
2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © 2001 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/"
|
||||
|
||||
3. Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.)
|
||||
|
||||
Original W3C files; http://www.w3.org/2001/06/soap-envelope
|
||||
Changes made:
|
||||
- reverted namespace to http://schemas.xmlsoap.org/soap/envelope/
|
||||
- reverted mustUnderstand to only allow 0 and 1 as lexical values
|
||||
- made encodingStyle a global attribute 20020825
|
||||
- removed default value from mustUnderstand attribute declaration
|
||||
|
||||
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
|
||||
|
||||
COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
|
||||
|
||||
The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.
|
||||
|
||||
-->
|
||||
<xs:chema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
targetNamespace="http://schemas.xmlsoap.org/soap/envelope/" >
|
||||
|
||||
|
||||
<!-- Envelope, header and body -->
|
||||
<xs:element name="Envelope" type="tns:Envelope" />
|
||||
<xs:complexType name="Envelope" >
|
||||
<xs:sequence>
|
||||
<xs:element ref="tns:Header" minOccurs="0" />
|
||||
<xs:element ref="tns:Body" minOccurs="1" />
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="Header" type="tns:Header" />
|
||||
<xs:complexType name="Header" >
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="Body" type="tns:Body" />
|
||||
<xs:complexType name="Body" >
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##any" processContents="lax" >
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Prose in the spec does not specify that attributes are allowed on the Body element
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:anyAttribute>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
<!-- Global Attributes. The following attributes are intended to be usable via qualified attribute names on any complex type referencing them. -->
|
||||
<xs:attribute name="mustUnderstand" >
|
||||
<xs:simpleType>
|
||||
<xs:restriction base='xs:boolean'>
|
||||
<xs:pattern value='0|1' />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="actor" type="xs:anyURI" />
|
||||
|
||||
<xs:simpleType name="encodingStyle" >
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:list itemType="xs:anyURI" />
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:attribute name="encodingStyle" type="tns:encodingStyle" />
|
||||
<xs:attributeGroup name="encodingStyle" >
|
||||
<xs:attribute ref="tns:encodingStyle" />
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:element name="Fault" type="tns:Fault" />
|
||||
<xs:complexType name="Fault" final="extension" >
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Fault reporting structure
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="faultcode" type="xs:QName" />
|
||||
<xs:element name="faultstring" type="xs:string" />
|
||||
<xs:element name="faultactor" type="xs:anyURI" minOccurs="0" />
|
||||
<xs:element name="detail" type="tns:detail" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="detail">
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##any" processContents="lax" />
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
8
tests/regression/server_root/conf/SoapEnvelope.dtd
Normal file
8
tests/regression/server_root/conf/SoapEnvelope.dtd
Normal file
@@ -0,0 +1,8 @@
|
||||
<!-- A stupid Soap DTD example -->
|
||||
<!ELEMENT Envelope (Header?,Body)>
|
||||
<!ELEMENT Header (#PCDATA)>
|
||||
<!ELEMENT Body (getInput)>
|
||||
|
||||
<!ELEMENT getInput (id)>
|
||||
<!ELEMENT id (#PCDATA)>
|
||||
<!ATTLIST id type CDATA #REQUIRED>
|
126
tests/regression/server_root/conf/SoapEnvelope.xsd
Normal file
126
tests/regression/server_root/conf/SoapEnvelope.xsd
Normal file
@@ -0,0 +1,126 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
|
||||
<!-- Schema for the SOAP/1.1 envelope
|
||||
|
||||
Portions © 2001 DevelopMentor.
|
||||
© 2001 W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved.
|
||||
|
||||
This document is governed by the W3C Software License [1] as described in the FAQ [2].
|
||||
[1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
|
||||
[2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
|
||||
By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make:
|
||||
|
||||
1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
|
||||
|
||||
2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © 2001 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/"
|
||||
|
||||
3. Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.)
|
||||
|
||||
Original W3C files; http://www.w3.org/2001/06/soap-envelope
|
||||
Changes made:
|
||||
- reverted namespace to http://schemas.xmlsoap.org/soap/envelope/
|
||||
- reverted mustUnderstand to only allow 0 and 1 as lexical values
|
||||
- made encodingStyle a global attribute 20020825
|
||||
- removed default value from mustUnderstand attribute declaration
|
||||
|
||||
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
|
||||
|
||||
COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
|
||||
|
||||
The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.
|
||||
|
||||
-->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
targetNamespace="http://schemas.xmlsoap.org/soap/envelope/" >
|
||||
|
||||
|
||||
<!-- Envelope, header and body -->
|
||||
<xs:element name="Envelope" type="tns:Envelope" />
|
||||
<xs:complexType name="Envelope" >
|
||||
<xs:sequence>
|
||||
<xs:element ref="tns:Header" minOccurs="0" />
|
||||
<xs:element ref="tns:Body" minOccurs="1" />
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="Header" type="tns:Header" />
|
||||
<xs:complexType name="Header" >
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="Body" type="tns:Body" />
|
||||
<xs:complexType name="Body" >
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##any" processContents="lax" >
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Prose in the spec does not specify that attributes are allowed on the Body element
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:anyAttribute>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
<!-- Global Attributes. The following attributes are intended to be usable via qualified attribute names on any complex type referencing them. -->
|
||||
<xs:attribute name="mustUnderstand" >
|
||||
<xs:simpleType>
|
||||
<xs:restriction base='xs:boolean'>
|
||||
<xs:pattern value='0|1' />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="actor" type="xs:anyURI" />
|
||||
|
||||
<xs:simpleType name="encodingStyle" >
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:list itemType="xs:anyURI" />
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:attribute name="encodingStyle" type="tns:encodingStyle" />
|
||||
<xs:attributeGroup name="encodingStyle" >
|
||||
<xs:attribute ref="tns:encodingStyle" />
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:element name="Fault" type="tns:Fault" />
|
||||
<xs:complexType name="Fault" final="extension" >
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Fault reporting structure
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="faultcode" type="xs:QName" />
|
||||
<xs:element name="faultstring" type="xs:string" />
|
||||
<xs:element name="faultactor" type="xs:anyURI" minOccurs="0" />
|
||||
<xs:element name="detail" type="tns:detail" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="detail">
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##any" processContents="lax" />
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
37
tests/regression/server_root/conf/httpd.conf.in
Normal file
37
tests/regression/server_root/conf/httpd.conf.in
Normal file
@@ -0,0 +1,37 @@
|
||||
### Base configuration for starting Apache httpd
|
||||
|
||||
<IfDefine !CHROOT>
|
||||
# File locations
|
||||
PidFile @MSC_REGRESSION_LOGS_DIR@/httpd.pid
|
||||
ScoreBoardFile @MSC_REGRESSION_LOGS_DIR@/httpd.scoreboard
|
||||
</IfDefine>
|
||||
|
||||
<IfModule !mod_proxy.c>
|
||||
LoadModule proxy_module @APXS_LIBEXECDIR@/mod_proxy.so
|
||||
LoadModule proxy_http_module @APXS_LIBEXECDIR@/mod_proxy_http.so
|
||||
</IfModule>
|
||||
<IfModule !mod_unique_id.c>
|
||||
LoadModule unique_id_module @APXS_LIBEXECDIR@/mod_unique_id.so
|
||||
</IfModule>
|
||||
|
||||
<IfDefine !NOMODSEC>
|
||||
# TODO: Need to have these configurable
|
||||
LoadFile /usr/lib/libxml2.so
|
||||
LoadFile /usr/lib/liblua5.1.so
|
||||
LoadModule security2_module @APXS_LIBEXECDIR@/mod_security2.so
|
||||
</IfDefine>
|
||||
|
||||
ServerName localhost
|
||||
|
||||
CoreDumpDirectory @MSC_REGRESSION_SERVERROOT_DIR@/tmp
|
||||
|
||||
LogLevel debug
|
||||
ErrorLog @MSC_REGRESSION_LOGS_DIR@/error.log
|
||||
|
||||
<IfDefine !CHROOT>
|
||||
DocumentRoot @MSC_REGRESSION_DOCROOT_DIR@
|
||||
<Directory "@MSC_REGRESSION_DOCROOT_DIR@">
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
</IfDefine>
|
14
tests/regression/server_root/conf/match.lua
Normal file
14
tests/regression/server_root/conf/match.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Test matching Lua Script to just print debug messages
|
||||
function main()
|
||||
m.log(1, "Test message.");
|
||||
m.log(2, "Test message.");
|
||||
m.log(3, "Test message.");
|
||||
m.log(4, "Test message.");
|
||||
m.log(5, "Test message.");
|
||||
m.log(6, "Test message.");
|
||||
m.log(7, "Test message.");
|
||||
m.log(8, "Test message.");
|
||||
m.log(9, "Test message.");
|
||||
|
||||
return "Lua script matched.";
|
||||
end
|
14
tests/regression/server_root/conf/test.lua
Normal file
14
tests/regression/server_root/conf/test.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Test Lua Script to just print debug messages
|
||||
function main()
|
||||
m.log(1, "Test message.");
|
||||
m.log(2, "Test message.");
|
||||
m.log(3, "Test message.");
|
||||
m.log(4, "Test message.");
|
||||
m.log(5, "Test message.");
|
||||
m.log(6, "Test message.");
|
||||
m.log(7, "Test message.");
|
||||
m.log(8, "Test message.");
|
||||
m.log(9, "Test message.");
|
||||
|
||||
return nil;
|
||||
end
|
0
tests/regression/server_root/data/.empty
Normal file
0
tests/regression/server_root/data/.empty
Normal file
0
tests/regression/server_root/data/ip.dir
Normal file
0
tests/regression/server_root/data/ip.dir
Normal file
BIN
tests/regression/server_root/data/ip.pag
Normal file
BIN
tests/regression/server_root/data/ip.pag
Normal file
Binary file not shown.
BIN
tests/regression/server_root/htdocs/8k.txt
Normal file
BIN
tests/regression/server_root/htdocs/8k.txt
Normal file
Binary file not shown.
1
tests/regression/server_root/htdocs/index.html
Normal file
1
tests/regression/server_root/htdocs/index.html
Normal file
@@ -0,0 +1 @@
|
||||
INDEX
|
BIN
tests/regression/server_root/htdocs/test.pdf
Normal file
BIN
tests/regression/server_root/htdocs/test.pdf
Normal file
Binary file not shown.
1
tests/regression/server_root/htdocs/test.txt
Normal file
1
tests/regression/server_root/htdocs/test.txt
Normal file
@@ -0,0 +1 @@
|
||||
TEST
|
1
tests/regression/server_root/htdocs/test2.txt
Normal file
1
tests/regression/server_root/htdocs/test2.txt
Normal file
@@ -0,0 +1 @@
|
||||
TEST 2
|
0
tests/regression/server_root/logs/audit/.empty
Normal file
0
tests/regression/server_root/logs/audit/.empty
Normal file
0
tests/regression/server_root/logs/subdir/.empty
Normal file
0
tests/regression/server_root/logs/subdir/.empty
Normal file
0
tests/regression/server_root/tmp/.empty
Normal file
0
tests/regression/server_root/tmp/.empty
Normal file
0
tests/regression/server_root/upload/.empty
Normal file
0
tests/regression/server_root/upload/.empty
Normal file
577
tests/regression/target/00-targets.t
Normal file
577
tests/regression/target/00-targets.t
Normal file
@@ -0,0 +1,577 @@
|
||||
### Test basic targets
|
||||
|
||||
# ARGS
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS "val1" "phase:2,log,pass"
|
||||
SecRule ARGS "val2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "val1" at ARGS.*Pattern match "val2" at ARGS/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS "val1" "phase:2,log,pass"
|
||||
SecRule ARGS "val2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "val1" at ARGS.*Pattern match "val2" at ARGS/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# ARGS_COMBINED_SIZE
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_COMBINED_SIZE (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule ARGS_COMBINED_SIZE "\@eq 16" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Operator EQ matched 16 at ARGS_COMBINED_SIZE\./s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_COMBINED_SIZE (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecRule ARGS_COMBINED_SIZE "\@eq 16" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Operator EQ matched 16 at ARGS_COMBINED_SIZE\./s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# ARGS_NAMES
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_NAMES (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_NAMES "arg1" "phase:2,log,pass"
|
||||
SecRule ARGS_NAMES "arg2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "arg1" at ARGS.*Pattern match "arg2" at ARGS/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_NAMES (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_NAMES "arg1" "phase:2,log,pass"
|
||||
SecRule ARGS_NAMES "arg2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "arg1" at ARGS_NAMES.*Pattern match "arg2" at ARGS_NAMES/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# ARGS_GET
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_GET (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_GET "val1" "phase:2,log,pass"
|
||||
SecRule ARGS_GET "val2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "val1" at ARGS_GET.*Pattern match "val2" at ARGS_GET/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_GET (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_GET "val1" "phase:2,log,pass"
|
||||
SecRule ARGS_GET "val2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Pattern match/, 1 ],
|
||||
debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# ARGS_GET_NAMES
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_GET_NAMES (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_GET_NAMES "arg1" "phase:2,log,pass"
|
||||
SecRule ARGS_GET_NAMES "arg2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "arg1" at ARGS_GET.*Pattern match "arg2" at ARGS_GET/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_GET_NAMES (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_GET_NAMES "arg1" "phase:2,log,pass"
|
||||
SecRule ARGS_GET_NAMES "arg2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Pattern match/, 1 ],
|
||||
debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# ARGS_POST
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_POST (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_POST "val1" "phase:2,log,pass"
|
||||
SecRule ARGS_POST "val2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Pattern match/, 1 ],
|
||||
debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_POST (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_POST "val1" "phase:2,log,pass"
|
||||
SecRule ARGS_POST "val2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "val1" at ARGS_POST.*Pattern match "val2" at ARGS_POST/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# ARGS_POST_NAMES
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_POST_NAMES (get)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_POST_NAMES "arg1" "phase:2,log,pass"
|
||||
SecRule ARGS_POST_NAMES "arg2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/Pattern match/, 1 ],
|
||||
debug => [ qr/Adding request argument \(QUERY_STRING\): name "arg1", value "val1".*Adding request argument \(QUERY_STRING\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "target",
|
||||
comment => "ARGS_POST_NAMES (post)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecRequestBodyAccess On
|
||||
SecResponseBodyAccess On
|
||||
SecResponseBodyMimeType null
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRule ARGS_POST_NAMES "arg1" "phase:2,log,pass"
|
||||
SecRule ARGS_POST_NAMES "arg2" "phase:2,log,pass"
|
||||
),
|
||||
match_log => {
|
||||
error => [ qr/Pattern match "arg1" at ARGS_POST.*Pattern match "arg2" at ARGS_POST/s, 1 ],
|
||||
debug => [ qr/Adding request argument \(BODY\): name "arg1", value "val1".*Adding request argument \(BODY\): name "arg2", value "val2"/s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "application/x-www-form-urlencoded",
|
||||
],
|
||||
"arg1=val1&arg2=val2",
|
||||
),
|
||||
},
|
||||
|
||||
# AUTH_TYPE
|
||||
#{
|
||||
# type => "target",
|
||||
# comment => "AUTH_TYPE",
|
||||
# conf => qq(
|
||||
# <IfVersion >= 2.2>
|
||||
# <IfModule !mod_authn_file.c>
|
||||
# LoadModule authn_file_module modules/mod_authn_file.so
|
||||
# </IfModule>
|
||||
# </IfVersion>
|
||||
## <IfVersion ~ ^2.0.>
|
||||
## <IfModule !mod_auth.c>
|
||||
## LoadModule auth_module modules/mod_auth.so
|
||||
## </IfModule>
|
||||
## </IfVersion>
|
||||
# <Location />
|
||||
# AuthType Basic
|
||||
# AuthName Test
|
||||
# AuthUserFile "$ENV{CONF_DIR}/htpasswd"
|
||||
# Require user nobody
|
||||
# </Location>
|
||||
# SecRuleEngine On
|
||||
# SecRequestBodyAccess On
|
||||
# SecResponseBodyAccess On
|
||||
# SecResponseBodyMimeType null
|
||||
## SecDebugLog $ENV{DEBUG_LOG}
|
||||
## SecDebugLogLevel 9
|
||||
# SecRule REQUEST_HEADERS:Authorization "Basic (.*)" "phase:2,log,pass,capture,chain"
|
||||
# SecRule TX:1 "nobody:test" "t:none,t:base64Decode,chain"
|
||||
# SecRule AUTH_TYPE "Basic"
|
||||
# ),
|
||||
# match_log => {
|
||||
# error => [ qr/Pattern match "Basic" at AUTH_TYPE/s, 1 ],
|
||||
# },
|
||||
# match_response => {
|
||||
# status => qr/^200$/,
|
||||
# },
|
||||
# request => new HTTP::Request(
|
||||
# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
# [
|
||||
# "Authorization" => "Basic bm9ib2R5OnRlc3Q="
|
||||
# ],
|
||||
# ),
|
||||
#},
|
||||
|
||||
## ENH: We cannot include this test as we cannot distribute the database.
|
||||
## Instead we should create a simple test DB of our own.
|
||||
## GEO
|
||||
#{
|
||||
# type => "target",
|
||||
# comment => "GEO (ip)",
|
||||
# conf => qq(
|
||||
# SecRuleEngine On
|
||||
# SecDebugLog $ENV{DEBUG_LOG}
|
||||
# SecDebugLogLevel 9
|
||||
# SecGeoLookupDB GeoLiteCity.dat
|
||||
# SecRule ARGS:ip "\@geoLookup" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:COUNTRY_CODE "\@streq US" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:COUNTRY_CODE3 "\@streq USA" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:COUNTRY_NAME "\@streq United States" "phase:2,log,pass,t:none"
|
||||
# # ENH: Not in this database?
|
||||
# SecRule GEO:COUNTRY_CONTINENT "\@streq NA" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:REGION "\@streq CA" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:CITY "\@streq San Diego" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:POSTAL_CODE "\@streq 92123" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:LATITUDE "\@beginsWith 32.8" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:LONGITUDE "\@beginsWith 117.1" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:DMA_CODE "\@streq 825" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:AREA_CODE "\@streq 858" "phase:2,log,pass,t:none"
|
||||
# ),
|
||||
# match_log => {
|
||||
# debug => [ qr/Geo lookup for "216.75.21.122" succeeded.*match "US" at GEO:COUNTRY_CODE.*match "USA" at GEO:COUNTRY_CODE3.*match "United States" at GEO:COUNTRY_NAME.*match "NA" at GEO:COUNTRY_CONTINENT.*match "CA" at GEO:REGION.*match "San Diego" at GEO:CITY.*match "92123" at GEO:POSTAL_CODE.*match "32.8" at GEO:LATITUDE.*match "825" at GEO:DMA_CODE.*match "858" at GEO:AREA_CODE/si, 1 ],
|
||||
# },
|
||||
# match_response => {
|
||||
# status => qr/^200$/,
|
||||
# },
|
||||
# request => new HTTP::Request(
|
||||
# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?ip=216.75.21.122",
|
||||
# ),
|
||||
#},
|
||||
#{
|
||||
# type => "target",
|
||||
# comment => "GEO (host)",
|
||||
# conf => qq(
|
||||
# SecRuleEngine On
|
||||
# SecDebugLog $ENV{DEBUG_LOG}
|
||||
# SecDebugLogLevel 9
|
||||
# SecGeoLookupDB GeoLiteCity.dat
|
||||
# SecRule ARGS:host "\@geoLookup" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:COUNTRY_CODE "\@streq US" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:COUNTRY_CODE3 "\@streq USA" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:COUNTRY_NAME "\@streq United States" "phase:2,log,pass,t:none"
|
||||
# # ENH: Not in this database?
|
||||
# SecRule GEO:COUNTRY_CONTINENT "\@streq NA" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:REGION "\@streq CA" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:CITY "\@streq San Diego" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:POSTAL_CODE "\@streq 92123" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:LATITUDE "\@beginsWith 32.8" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:LONGITUDE "\@beginsWith 117.1" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:DMA_CODE "\@streq 825" "phase:2,log,pass,t:none"
|
||||
# SecRule GEO:AREA_CODE "\@streq 858" "phase:2,log,pass,t:none"
|
||||
# ),
|
||||
# match_log => {
|
||||
# debug => [ qr/Using address "\d+\.\d+\.\d+\.\d+".*Geo lookup for "www\.modsecurity\.org" succeeded.*match "US" at GEO:COUNTRY_CODE.*match "USA" at GEO:COUNTRY_CODE3.*match "United States" at GEO:COUNTRY_NAME.*match "NA" at GEO:COUNTRY_CONTINENT.*match "CA" at GEO:REGION.*match "San Diego" at GEO:CITY.*match "92123" at GEO:POSTAL_CODE.*match "32.8" at GEO:LATITUDE.*match "825" at GEO:DMA_CODE.*match "858" at GEO:AREA_CODE/si, 1 ],
|
||||
# },
|
||||
# match_response => {
|
||||
# status => qr/^200$/,
|
||||
# },
|
||||
# request => new HTTP::Request(
|
||||
# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?host=www.modsecurity.org",
|
||||
# ),
|
||||
#},
|
||||
#{
|
||||
# type => "target",
|
||||
# comment => "GEO (failed lookup)",
|
||||
# conf => qq(
|
||||
# SecRuleEngine On
|
||||
# SecDebugLog $ENV{DEBUG_LOG}
|
||||
# SecDebugLogLevel 9
|
||||
# SecGeoLookupDB GeoLiteCity.dat
|
||||
# SecRule ARGS:ip "\@geoLookup" "phase:2,log,pass,t:none"
|
||||
# SecRule \&GEO "\@eq 0" "phase:2,log,deny,status:403,t:none"
|
||||
# SecRule ARGS:badip "\@geoLookup" "phase:2,log,pass,t:none"
|
||||
# SecRule \&GEO "!\@eq 0" "phase:2,log,deny,status:403,t:none"
|
||||
# ),
|
||||
# match_log => {
|
||||
# -debug => [ qr/Geo lookup for "127\.0\.0\.1" succeeded/si, 1 ],
|
||||
# },
|
||||
# match_response => {
|
||||
# status => qr/^200$/,
|
||||
# },
|
||||
# request => new HTTP::Request(
|
||||
# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt?ip=216.75.21.122&badip=127.0.0.1",
|
||||
# ),
|
||||
#},
|
||||
|
||||
# TODO: ENV
|
||||
# TODO: FILES
|
||||
# TODO: FILES_COMBINED_SIZE
|
||||
# TODO: FILES_NAMES
|
||||
# TODO: FILES_SIZES
|
||||
# TODO: FILES_TMPNAMES
|
||||
# TODO: HIGHEST_SEVERITY
|
||||
# TODO: MATCHED_VAR
|
||||
# TODO: MATCHED_VAR_NAME
|
||||
# TODO: MODSEC_BUILD
|
||||
# TODO: MULTIPART_CRLF_LF_LINES
|
||||
# TODO: MULTIPART_STRICT_ERROR
|
||||
# TODO: MULTIPART_UNMATCHED_BOUNDARY
|
||||
# TODO: PATH_INFO
|
||||
# TODO: QUERY_STRING
|
||||
# TODO: REMOTE_ADDR
|
||||
# TODO: REMOTE_HOST
|
||||
# TODO: REMOTE_PORT
|
||||
# TODO: REMOTE_USER
|
||||
# TODO: REQBODY_PROCESSOR
|
||||
# TODO: REQBODY_PROCESSOR_ERROR
|
||||
# TODO: REQBODY_PROCESSOR_ERROR_MSG
|
||||
# TODO: REQUEST_BASENAME
|
||||
# TODO: REQUEST_BODY
|
||||
# TODO: REQUEST_COOKIES
|
||||
# TODO: REQUEST_COOKIES_NAMES
|
||||
# TODO: REQUEST_FILENAME
|
||||
# TODO: REQUEST_HEADERS
|
||||
# TODO: REQUEST_HEADERS_NAMES
|
||||
# TODO: REQUEST_LINE
|
||||
# TODO: REQUEST_METHOD
|
||||
# TODO: REQUEST_PROTOCOL
|
||||
# TODO: REQUEST_URI
|
||||
# TODO: REQUEST_URI_RAW
|
||||
# TODO: RESPONSE_BODY
|
||||
# TODO: RESPONSE_CONTENT_LENGTH
|
||||
# TODO: RESPONSE_CONTENT_TYPE
|
||||
# TODO: RESPONSE_HEADERS
|
||||
# TODO: RESPONSE_HEADERS_NAMES
|
||||
# TODO: RESPONSE_PROTOCOL
|
||||
# TODO: RESPONSE_STATUS
|
||||
# TODO: RULE
|
||||
# TODO: SCRIPT_BASENAME
|
||||
# TODO: SCRIPT_FILENAME
|
||||
# TODO: SCRIPT_GID
|
||||
# TODO: SCRIPT_GROUPNAME
|
||||
# TODO: SCRIPT_MODE
|
||||
# TODO: SCRIPT_UID
|
||||
# TODO: SCRIPT_USERNAME
|
||||
# TODO: SERVER_ADDR
|
||||
# TODO: SERVER_NAME
|
||||
# TODO: SERVER_PORT
|
||||
# TODO: SESSION
|
||||
# TODO: SESSIONID
|
||||
# TODO: TIME
|
||||
# TODO: TIME_DAY
|
||||
# TODO: TIME_EPOCH
|
||||
# TODO: TIME_HOUR
|
||||
# TODO: TIME_MIN
|
||||
# TODO: TIME_MON
|
||||
# TODO: TIME_SEC
|
||||
# TODO: TIME_WDAY
|
||||
# TODO: TIME_YEAR
|
||||
# TODO: TX
|
||||
# TODO: USERID
|
||||
# TODO: WEBAPPID
|
||||
# TODO: WEBSERVER_ERROR_LOG
|
||||
# TODO: XML
|
||||
|
Reference in New Issue
Block a user