How to prevent content-spoofing in Apache's 404 error pages

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, November 20, 2019

Follow me on Twitter as @mattiasgeniar

We had an interesting security report for our Oh Dear monitoring service. An attacker could load a specific URL and trigger a 404 page in which they controlled the output.

What content spoofing in a 404 page looks like

The URL looked like this.

https://ohdear.app/%2f%20This%20site%20is%20on%20maintenance%20Please%20visit%20www.devil.com%20because%20this%20site

If you decode that, you can see that the %2f is a specially encoded path separator. The URL decoded version looks like this.

https://ohdear.app// This site is on maintenance Please visit www.devil.com because this site

You’d think Apache handles that OK by default, but it doesn’t. We have a custom 404 error page, but the URL above triggered this one.

404 content spoofing error page

What’s worrying here is that the attacker controls the text on the page, because the default 404 confirms the page URL right in the HTML body.

And since many browsers decide on hiding the URL in the address bar and just show the domain name instead, it isn’t immediately obvious the URL has been tampered with.

Preventing content spoofing in Apache’s 404 error page

Chances are, your website is vulnerable to this too. Copy/paste the URL above and see what kind of error page you get.

The fix is to apply a little-known Apache config called AllowEncodedSlashes and set it to AllowEncodedSlashes NoDecode.

There appears to be a bug in Apache that requires you to set this in every VirtualHost because globally defined configs aren’t inherited to VirtualHosts.

In other words: copy this to every every VirtualHost you have.

<VirtualHost *:80>
  [...]

  AllowEncodedSlashes NoDecode

</VirtualHost>

After you add that config and reload the Apache daemon, you’ll be served either your custom 404 page (the one you were expecting) or a cleaned up 404 page of Apache.

404 content spoofing error page

It surprises me this is isn’t a default config in Apache though.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.