Navigating mod_rewrite pitfall when running on Tomcat 9

Hi,

This is just to let others who may face a similar issue know about the workaround.

We have very special requirements in our Apache/Tomcat/Lucee setup which force us to use mod_rewrite’s RewriteRules exlusively to hand requests over to Tomcat via AJP. I have discovered that at least on a current Debian 11.3 (Bullseye) Apache 2.4.53-1~deb11u1, mod_rewrite’s P-flag will sometimes not pass the secret we configured for the AJP-worker. This must definitely be a bug in the Apache codebase. There is a way to avoid compromising security, though.

In Tomcat 9 it has become the default setting (and good practice, too) to set a secret for the AJP connector like so (in Tomcat’s server.xml):

<Connector address="127.0.0.1" 
  	port="8009"
  	protocol="AJP/1.3"
  	redirectPort="8443"
  	secretRequired="true"
  	secret="youllneverknow"
  	enableLookups="false"
  	tomcatAuthentication="false"
  	allowedRequestAttributesPattern=".*"
  	packetSize="65536"
  	maxHttpHeaderSize="65536"
  	URIEncoding="UTF-8" />

In order to pass that secret from Apache, I originally declared a worker in Apache’s mods-available/proxy.conf like so:

<Proxy "ajp://localhost:8009">
	ProxySet secret=youllneverknow
</Proxy>

A typical rewrite rule simply uses this worker, for example:

RewriteRule ^/?(.*?)(?:(?<=/)optionalpostfix/)?$ ajp://localhost:8009/$ajpPath/index.cfm?rewrite=$1&%{QUERY_STRING} [P,L,env=AJP_REDIRECT_REAL_URL:$1]

This is working fine - for most cases. We have one case, where mod_rewrite would need to process a fair number of prior RewriteCond statements before actually getting to the last and desired RewriteRule. This RewriteRule would in fact be exactly the same for two subsequent cases with only the variable $ajpPath changed in between, so P-flag in place and the same AJP-worker. For the first case, everything was working fine, for the second case some RewriteCond’s later, Tomcat would send a 403 status, so it seems like mod_rewrite does not honour the worker configuration in some cases. It would work fine again, when Tomcat would be set to secretRequired=false as some guides for setting up Apache and Tomcat still suggest, however I felt like this was giving up.

I therefore removed the worker-config from mods-available/proxy.conf altogether. Instead I enabled the mods proxy_balancer, slotmem_shm and lbmethod_byrequests. Then I set up a balancer with a single node in mods-available/proxy_balancer.conf:

<Proxy balancer://tomcat>
	BalancerMember ajp://localhost:8009 secret=youllneverknow
</Proxy>

And replaced the target in the RewriteRules accordingly:

RewriteRule ^/?(.*?)(?:(?<=/)optionalpostfix/)?$ balancer://tomcat/$ajpPath/index.cfm?rewrite=$1&%{QUERY_STRING} [P,L,env=AJP_REDIRECT_REAL_URL:$1]

This is working fine now, regardless of the complexity of the mod_rewrite processing. I hope this helps somebody facing the same issue.