Deny Access to a Directory with IIS

Apache is the dominant server for PHP content although IIS can be a respectable substitute. However, upon first inspection IIS does not appear to be as flexible as Apache, particularly regarding dynamic configuration through .htaccess. There are generally three main areas where .htaccess files are used:

  • URL rewriting
  • Providing basic or digest authentication
  • Denying access to a directory

The CodeIgniter framework for example contains an .htaccess file in the root of the application and system folders to deny direct access to important site resources. Additionally, we may wish to have an uploads folder where file access is managed through our PHP application; we cannot use ACLs in such an example as the anonymous IIS user must have access to the resource yet the client should not be able to access it directly.

Apache lets us define this behavior easily by adding one line to an .htaccess file in the protected directory:

deny from all

The client will now receive a 403 Forbidden error should they try to to access the directory or any resource within. ASP.NET developers may use forms or windows authentication to address the problem but these are not easily available from a PHP application. Luckily IIS 7 includes a Request Filtering module which allows us to deny access to a directory using a web.config file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <denyUrlSequences>
                    <add sequence="/" />
                </denyUrlSequences>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>

This configuration will send the client a 404.5 Not Found status. While the status code is not as accurate as Apache’s 403 status, it does at least prevent access to the directory and it’s resources.

Continue reading

IIS Directory Permissions and File Uploads

IIS 7 requires the following user accounts to have read access to your webroot: IIS_IUSRS and IUSR. For a typical ASP.NET application IIS_IUSRS may also be granted write permissions for specific directories or files. However, if impersonation is used (e.g. fastcgi.impersonate is recommended for PHP), then the IUSR account must also be granted write permissions to the resources.

The following command-line actions will set the permissions correctly (note: replace C:\inetpub\wwroot with your webroot):

ICACLS "C:\inetpub\wwwroot" /Grant "IIS_IUSRS":(OI)(CI)M
ICACLS "C:\inetpub\wwwroot" /Grant "IUSR":(OI)(CI)M

Rewriting WordPress from a Subdirectory

Running WordPress from a subdirectory keeps a websites root directory clean and allows easy separation from other unrelated content. However, this will result in a longer url e.g. http://ajmm.org/wordpress/ rather than http://ajmm.org/. Fortunately, it is possible to maintain this directory structure yet host WordPress using the shorter root url.

The instructions provided by the WordPress Codex provide one way to do so but the method is more complicated than necessary when considering the rewrite ability of modern webservers. Provided below are rewrite rules for Apache, IIS and nginx which do not require editing any WordPress files.

Note: all configurations assume that WordPress is hosted in a subdirectory called wordpress. Apache and IIS rules should be applied to the root folder only.

Apache .htaccess

<IfModule mod_rewrite.c>

    RewriteEngine On

    # Rewrite empty requests to the wordpress
    # index page rather than trying to display
    # a directory listing.
    RewriteRule ^$ wordpress/index.php [L]

    # Rewrite requests to the wordpress directory
    # when the resource cannot be found.
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ wordpress/$1

    # Rewrite requests to the wordpress index page
    # if the resource still cannot be found.
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ wordpress/index.php [L]

</IfModule>

IIS web.config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <directoryBrowse enabled="true" />
    <rewrite>
      <rules>
        <rule name="Wordpress Index Rewrite" stopProcessing="true">
          <match url="^$" ignoreCase="false" />
          <action type="Rewrite" url="wordpress/index.php" />
        </rule>
        <rule name="Wordpress Hard Rewrite" stopProcessing="false">
          <match url="^(.*)$" ignoreCase="false" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
          </conditions>
          <action type="Rewrite" url="wordpress/{R:1}" />
        </rule>
        <rule name="Wordpress Soft Rewrite" stopProcessing="true">
          <match url="^(.*)$" ignoreCase="false" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
          </conditions>
          <action type="Rewrite" url="wordpress/index.php" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

nginx

location / {
  try_files $uri $uri/ /wordpress$uri?$args;
}

location /wordpress {
  index index.php;
  try_files $uri $uri/ /wordpress/index.php;
}