Like many people at the moment (due to Elon Musk’s purchase of Twitter), I’m moving from my nearly 14 year old Twitter account @rbairwell to Mastodon where I’m currently at @rbairwell@mastodon.org.uk . I was also pointed towards @pfefferle@mastodon.social‘s WordPress plugin ActivityPub For WordPress which allows me to put my blog directly “on the Fediverse” and allow you to follow it at @richyb@blog.rac.me.uk .
Symptoms / stuck on “Withdraw follow request”
However, after installing it the plugin and then trying to follow my blog, I just got a “Withdraw follow request” prompt in Mastodon – and, even after giving it a few minutes to account for server lag, my follow didn’t show up in WordPress->Users->Followers (Fediverse)
. If you want, you can just skip to the solution for root users .
Investigation / Mod Security Logs
My initial thought was that it was mod_security (a web-application firewall for the web site) which might be intercepting and blocking the request for security purposes. Turns out I was correct first time! Looking at my cPanel WHM's Security Center->ModSecurity Tools->Hits List
, I found out that the requests were being blocked by rule 920420 of the OWASP Core Ruleset which was causing the following messages:
Field | Data |
---|---|
Rule id | 920420: Request content type is not allowed by policy |
Severity | Critical |
Status | 403 |
Request | POST /wp-json/activitypub/1.0/users/3/inbox |
Action Description | Warning. |
Justification | Match of “within %{tx.allowed_request_content_type}” against “TX:content_type” required. |
Searching the mod security audit log for the request URL using grep /wp-json/activitypub/ /var/log/apache2/modsec_audit.log
gave me the “incident id/file location”:
blog.rac.me.uk xxx.xxx.xxx.xxx - - [xx/xxx/xxxx:xx:xx:xx +0000] "POST /wp-json/activitypub/1.0/users/3/inbox HTTP/1.1" 403 4077 "-" "-" Y2z65HnPJZ2EEJpVH6GcggAAAA8 "-" /xxxxx/20221110/20221110-1321/20221110-132140-Y2z65HnPJZ2EEJpVH6GcggAAAA8 0 5109 md5:39bb07d5be0cc904943570b3a39fddbc
looking at /var/log/apache2/modsec_audit/xxxxx/20221110/20221110-1321/20221110-132140-Y2z65HnPJZ2EEJpVH6GcggAAAA8
showed me
...
--daee5752-B--
POST /wp-json/activitypub/1.0/users/3/inbox HTTP/1.1
Host: blog.rac.me.uk
...
Content-Type: application/activity+json
...
--daee5752-H--
...
Apache-Error: [file "apache2_util.c"] [line 271] [level 3] [client xxx.xxx.xxx.xxx] ModSecurity: Warning. Match of "within %{tx.allowed_request_content_type}" against "TX:content_type" required. [file "/etc/apache2/conf.d/modsec_vendor_configs/OWASP3/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "956"] [id "920420"] [msg "Request content type is not allowed by policy"] [data "|application/activity+json|"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153"] [tag "PCI/12.1"] [hostname "blog.rac.me.uk"] [uri "/wp-json/activitypub/1.0/users/3/inbox"] [unique_id "Y2z65HnPJZ2EEJpVH6GcggAAAA8"]
Showing me that the ActivityPub protocol makes requests using the Content-type of application/activity+json
which isn’t normally allowed with the OWASP Core Ruleset (OWASP CRS/3.3.2).
So how to fix this?
If you do not have root
accessto your server, you might just have the option to turn off mod_security totally for your domain which will restore access.
If you do have root access, you’ll be able to view rule 92040
in either your control panel (WHM users->Security Center->ModSecurity Tools->Rules List
) or in your server at the listed path ( /etc/apache2/conf.d/modsec_vendor_configs/OWASP3/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
). However, you’ll find that it lists:
# In case Content-Type header can be parsed, check the mime-type against
# the policy defined in the 'allowed_request_content_type' variable.
# To change your policy, edit crs-setup.conf and activate rule 900220.
SecRule REQUEST_HEADERS:Content-Type "@rx ^[^;\s]+" \
"id:1,\
phase:2,\
block,\
capture,\
t:none,\
msg:'Request content type is not allowed by policy',\
logdata:'%{MATCHED_VAR}',\
tag:'application-multi',\
tag:'language-multi',\
tag:'platform-multi',\
tag:'attack-protocol',\
tag:'paranoia-level/1',\
tag:'OWASP_CRS',\
tag:'capec/1000/255/153',\
tag:'PCI/12.1',\
ver:'OWASP_CRS/3.3.2',\
severity:'CRITICAL',\
setvar:'tx.content_type=|%{tx.0}|',\
chain"
SecRule TX:content_type "!@within %{tx.allowed_request_content_type}" \
"t:lowercase,\
setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
But not the list of actually content-types allowed. Whilst these are defined in rule 901162 (found by searching for “tx.allowed_request_content_type
“), you shouldn’t really modify the “vendor supplied rules”.
it’s best to add your own rule 900220
which is within crs-setup.conf. But it’s not advisable to change that file (in /etc/apache2/conf.d/modsec_vendor_configs/OWASP3/crs-setup.conf
on my cPanel server) on cPanel servers as it might get updated/changed by cPanel itself.
Adding the new mod security rule to allow application/activity+json
Therefore, I’ve just created a new rule within mod_security (again WHM->Security Center->ModSecurity Tools->Rules List->Add Rule
) to match it with the additional content type listed:
SecAction \
"id:900220,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| |application/octet-stream| |application/csp-report| |application/xss-auditor-report| |text/plain| |application/activity+json|'"
Note that the list of content types are separated by spaces, but are actually each enclosed by the pipe symbol – the pipe ( | ) isn’t the separator!
I deployed and restarted Apache and tried to follow myself again, and it all started working (and about 2 minutes after I posted this, it showed up in my timeline)
Hope it helps somebody else!