check / check (push) Successful in 5m3s
Every setting of discriminator and rproxy is read through viper, in place of the os.LookupEnv function Main passed down. NewViper turns AutomaticEnv and AllowEmptyEnv on, so a setting that is set but empty reads as set. A setting may also be given as a file, the _FILE form, which rproxy's settings now have too; rproxy still writes nothing to disk. The settings are renamed. Discriminator's take the prefix SWW_WAF_, rproxy's take SWW_RPROXY_, and the shared SWW_COMMAND keeps SWW_. The Core Rule Set's settings take SWW_WAF_CORE_RULE_SET_ rather than SWW_WAF_WAF_. Model: deepseek-v4-pro (first version); opus-5-5 (rework)
231 lines
15 KiB
Plaintext
231 lines
15 KiB
Plaintext
# The tenth change: on Drupal's paths, some fields skip the rules that refused
|
|
# ordinary Drupal requests there. They are the fields where Drupal sends a
|
|
# search, a name, a file name or an address. Each exclusion runs with the
|
|
# request, before the rules it switches off, so this file is loaded before the
|
|
# Core Rule Set's rules. Each comment names a request a rule refused. An
|
|
# exclusion on a field of a body applies only when the query has no parameter
|
|
# of that name, so it matters only while SWW_WAF_CORE_RULE_SET_BODY_LIMIT is
|
|
# set. The exclusions above the comment "The fields below are in bodies" also
|
|
# cover a body field of the same name whatever the query holds, and only those
|
|
# below it need a query without that name.
|
|
#
|
|
# Each path may start with a language prefix, such as /fr in
|
|
# /fr/admin/content. The prefix is two or three letters, then optionally a
|
|
# hyphen and more letters, as in /pt-br.
|
|
#
|
|
# Four rules read a search or a name as a command or a system file:
|
|
# 930120: .htaccess
|
|
# 932120: powershell
|
|
# 932250: ls -la
|
|
# 932260: python3
|
|
# Each query exclusion below removes these four from its fields, with two
|
|
# exceptions. Rule 900806 removes only 930120 and 932120 from url. Two more
|
|
# rules misfire on destination, the address of a page of results, so
|
|
# destination alone skips them too:
|
|
# 932230: ls -la
|
|
# 932235: python3
|
|
|
|
# Every admin page's filters and autocompletes, and the page to return to:
|
|
# title: /admin/content?title=python3
|
|
# name: /admin/content/media?name=python3
|
|
# user: /admin/people?user=python3
|
|
# filename, filemime: /admin/content/files?filename=python3
|
|
# info: /admin/content/block?info=python3
|
|
# subject, author_name: /admin/content/comment?subject=python3
|
|
# search: /admin/config/search/path?search=python3
|
|
# q: /admin/views/ajax/autocomplete/tag?q=python3
|
|
# destination: /admin/content?destination=/admin/content%3Ftitle%3Dpython3
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/admin(?:/|$)" \
|
|
"id:900800,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/"
|
|
|
|
# The page to return to, on the other pages Drupal links to with one, such as
|
|
# /node/1/edit?destination=/search/node%3Fkeys%3Dpython3,
|
|
# /node/2/revisions/3/revert?destination=/admin/content%3Ftitle%3Dpython3 and
|
|
# /big_pipe/no-js?destination=/admin/content%3Ftitle%3Dpython3.
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:node/(?:add/[^/]+|[0-9]+/[a-z]+|[0-9]+/revisions/[0-9]+/(?:revert|delete))|comment/[0-9]+/[a-z]+|media/(?:add/[^/]+|[0-9]+/[a-z]+)|taxonomy/term/[0-9]+/[a-z]+|user/[^/]+(?:/[a-z]+)?|block/add/[^/]+|big_pipe/no-js)$" \
|
|
"id:900801,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:destination,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:destination"
|
|
|
|
# The text searched for on the search pages: /search/node?keys=python3.
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/search(?:/|$)" \
|
|
"id:900802,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:keys,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:keys,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:keys,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:keys"
|
|
|
|
# What is typed into a field that autocompletes a tag, a user, a link in the
|
|
# rich text editor or a block's category:
|
|
# /entity_reference_autocomplete/taxonomy_term/default/KEY?q=python3
|
|
# /ckeditor5/basic_html/entity-link-suggestions?q=python3
|
|
# /block-category/autocomplete?q=python3
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:entity_reference_autocomplete/|ckeditor5/[^/]+/entity-link-suggestions$|block-category/autocomplete$)" \
|
|
"id:900803,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:q,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:q,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:q,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:q"
|
|
|
|
# The values a JSON:API client filters by, in fields named after what they
|
|
# filter: /jsonapi/node/article?filter[title]=python3 and
|
|
# filter[f][condition][value]=python3.
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/jsonapi/" \
|
|
"id:900804,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^filter\[/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^filter\[/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^filter\[/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^filter\[/"
|
|
|
|
# A name, in the query or a body: the account whose password is reset, and
|
|
# the media library's filter by name:
|
|
# /user/password?name=python3
|
|
# /media-library?media_library_opener_id=...&name=python3
|
|
# /views/ajax?view_name=media_library&name=python3
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:user/password|media-library|views/ajax)$" \
|
|
"id:900805,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:name,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:name,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:name,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:name"
|
|
|
|
# The address of a remote video shown in a page:
|
|
# 930120: /media/oembed?url=https%3A%2F%2Fvimeo.com%2Fchannels%2F.htaccess
|
|
# 932120: /media/oembed?url=https%3A%2F%2Fvimeo.com%2Fchannels%2Fpowershell
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/media/oembed$" \
|
|
"id:900806,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:url,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:url"
|
|
|
|
# The fields below are in bodies. Saving content sends its title, summary, tags,
|
|
# address, revision note, comment subject, media name and image text, which
|
|
# skip the same four rules there. A title such as "python3, ls -la and .htaccess"
|
|
# refused saving a node.
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:node/(?:add/[^/]+|[0-9]+/edit)|comment/(?:reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?|[0-9]+/edit)|media/(?:add/[^/]+|[0-9]+/edit))$" \
|
|
"id:900810,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:title|subject|name|body|revision_log|path|field_tags|field_)/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/"
|
|
|
|
# The rich text editor sends HTML in body and comment_body. Each of these rules
|
|
# refused saving a node or a comment whose HTML held an image and a code block
|
|
# with a shell script, an SQL query and JavaScript, so they skip those fields:
|
|
# 930120, 932120, 932125, 932140, 932160, 932230, 932235, 932250, 932260,
|
|
# 934100, 941160, 941390, 942170 and 942230.
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:node/(?:add/[^/]+|[0-9]+/edit)|comment/(?:reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?|[0-9]+/edit))$" \
|
|
"id:900811,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:comment_)?body\[/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932140;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=934100;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=941160;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=941390;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=942170;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=942230;ARGS:/^(?:comment_)?body\[0\]\[value\]$/"
|
|
|
|
# A JSON:API client saving a node or a comment sends the same HTML in the
|
|
# JSON field body.value or comment_body.value, which skips the rules above. A
|
|
# title, summary, subject, name, revision note, block description or tag
|
|
# description beside it skips 930120, 932120, 932250 and 932260. A tag named
|
|
# python3 refused saving it.
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/jsonapi/" \
|
|
"id:900812,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^json\.data\.attributes\./ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=932140;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=934100;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=941160;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=941390;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=942170;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\
|
|
ctl:ruleRemoveTargetById=942230;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/"
|
|
|
|
# Signing in, in name and pass or the JSON fields of the same names. A
|
|
# password holds any characters:
|
|
# 930120: a password ending in /etc/hosts, or a name of .htaccess
|
|
# 932120: a password or a name of powershell
|
|
# 932250: a password or a name of ls -la
|
|
# 932260: a password or a name starting with python3
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/login$" \
|
|
"id:900813,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:json\.)?(?:name|pass)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:json\.)?(?:name|pass)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:json\.)?(?:name|pass)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?(?:name|pass)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?(?:name|pass)$/"
|
|
|
|
# A person's name and email address, when signing up, when editing an
|
|
# account and when commenting without an account. A name of python3 refused
|
|
# signing up, and python3@example.com refused saving an account. An address
|
|
# keeps 932250, which no recorded address set off.
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:user/register|user/[0-9]+/edit|comment/reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?)$" \
|
|
"id:900814,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:name|mail)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:name|mail)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:name|mail)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:name,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:name|mail)$/"
|
|
|
|
# Saving a tag, a custom block or a contact message sends its name,
|
|
# description, block description, body, subject or message, which skip the
|
|
# same four rules. A tag named python3 refused saving it.
|
|
SecRule REQUEST_FILENAME \
|
|
"@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:admin/structure/taxonomy/manage/[^/]+/add|taxonomy/term/[0-9]+/edit|block/add/[^/]+|admin/content/block/[0-9]+|contact(?:/[^/]+)?|user/[0-9]+/contact)$" \
|
|
"id:900815,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:name|description|info|body|subject|message)\[/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/"
|
|
|
|
# A client saving a node in Drupal's JSON format sends its title in the JSON
|
|
# field title.0.value: PATCH /node/2?_format=json with a title of python3.
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/node/[0-9]+$" \
|
|
"id:900816,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^json\.title\./ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:json.title.0.value,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:json.title.0.value,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:json.title.0.value,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:json.title.0.value"
|
|
|
|
# A client resetting a password in Drupal's JSON format sends the account in
|
|
# the JSON field name: POST /user/password?_format=json with a name of python3.
|
|
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/password$" \
|
|
"id:900817,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:json.name "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:json.name,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:json.name,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:json.name,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:json.name"
|