Disallow direct access to PHP files in wp-content/uploads/

It’s recommended to disallow access to and execution of PHP files in wp-content/uploads folder. Preferably without the use of a security plugin. Blocking access to PHP files in WordPress wp-content/uploads folder is easily achieved with a .htaccess file on Linux Apache, or web.config accesssPolicy in Windows Server IIS, and here is how.

Secure wp-content/uploads in Linux Apache and Windows Server IIS

Block PHP execution in Windows Server IIS and Linux Apache

As said, it is recommended to deny PHP execution in folders like WordPress wp-content/uploads. A lot of malware is uploaded to that folder and used as and entry point. Additional malware and PHP backdoors are uploaded from there. So disable PHP execution in wp-content/uploads! I’ve written about securing WordPress uploads folder before.

Windows Server IIS web.config

The easiest method in IIS to disable PHP execution in a folder is to create a web.config file with an accessPolicy for handlers. Such an accessPolicy tells IIS what a PHP hander is allowed to do: execute, read, or read/write. Using this technique you disable the execution of PHP completely for that particular folder.

you’ll find more information about IIS Handlers in IIS’ documentation.

In IIS Manager:

  • In IIS Manager, click through to your web site
  • double click “Handler Mappings
  • search for PHP and double click
  • click Request Restrictions
  • click the tab Access
  • Set Script to Read
Set PHP handler accessPolicy (Request Restrictions) to Read in IIS

Did you know you can use Windows Server File Server Resource Manager File Screens to block the upload of vulnerable WordPress plugins? Read all about it in Deny vulnerable WordPress plugins using Windows Server File Server Resource Manager’s File Screens.

Using a web.config file directly.

Copy and paste the following XML into a new file and save it as web.config:

<?xml version="1.0" encoding="UTF-8"?>
		<!-- deny PHP execution per IIS accessPolicy -->
		<handlers accessPolicy="Read"/>

In PowerShell (and appcmd.exe), you can use the following PowerShell and appcmd.exe commands to configure an accessPolicy for handlers (where example.com is your website):

# PowerShell, WebAdministration
Set-WebConfiguration "/system.webServer/handlers/@accessPolicy" -value "Read" -PSPath "MACHINE/WEBROOT/APPHOST/example.com/wp-content/uploads"

# AppCmd.exe
appcmd.exe set config "example.com/wp-content/uploads" /section:handlers /accessPolicy:Read

Caveat: by setting an accessPolicy to “Read”, you basically disable all configured handlers, not just PHP.

Disable PHP execution in a selected directory on Linux Apache

There are several methods to disable PHP execution in Apache using a .htaccess file. I’ll mention them here in short:

SetHandler: use SetHandler default-handler to send the file using the default_handler(), which is the handler used by default to handle static content. It just renders the PHP as text. So be careful with this.

In your wp-content/uploads/.htaccess file, add:

# use <Files *> if appropriate
<Files *.php>
        SetHandler default-handler

Mod_authz_core .htaccess access control: you can deny access to PHP files using Apache access control in mod_authz_core module. It’ll send a 403 response for requests to *.php files. Add to your .htaccess file:

<Files *.php>
	# Apache 2.2
	<IfModule !mod_authz_core.c>
		Order Deny,Allow
		Deny from all
	# Apache 2.4.6+
	<IfModule mod_authz_core.c>
		Require all denied

Please note the IfModule condition whether the module mod_authz_core.c is available. This is important as explained in the above linked article.

Mod_Rewrite: rewrite and forbid requests to *.php files. It’s easy to use mod_rewrite to deny access to *.php files by rewriting those requests and sending a F|forbidden flag:

RewriteEngine On
RewriteRule ^.*.php$ - [F,L]

Why did I start this article with

Preferably without the use of a security plugin

Because most security plugins are easy to defeat, especially once you have access to the file system the website resides on (e.g WordPress admin, FTP access, and so on). The post Defeating WordPress Security Plugins (Revisited) by @TheXC3LL has some nice red teaming thoughts about this.

Hi! Join the discussion, leave a reply!

Loading time: 105 queries, 0.196 seconds using 13741496 bytes memory. Peak memory usage: 14140472 bytes.