How to prevent access to Drupal admin URL with Apache and mod_rewrite
In some Drupal sites, you want to disallow access to the administration interface at /admin. You can use Apache's mod_rewrite module to achieve this.
Let's say your Drupal website is available via two domain names, www.example.com and admin.example.com, where:
- www.example.com is the public side of the website. Anonymous and authenticated users have access to it. They are untrusted users.
- admin.example.com is a private area of the website. It uses SSL and may only be reachable by users within an intranet. Trusted users connect to the administration interface via the admin.example.com domain name.
Since there are no trusted users using www.example.com, you want to disallow access to some URL for that domain. As an example, you do not want /admin to be reachable on www.example.com. Site administrators have to connect through admin.example.com/user/login then be granted access to admin.example.com/admin.
First make sure you have separate virtual hosts for each domain. One for www.example.com, one for admin.example.com. Both hosts can reference the same Drupal document root.
Then add the following code in the www.example.com VirtualHost configuration:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} index.php [NC]
RewriteCond %{QUERY_STRING} (^|&)q=admin(/|&|$) [NC]
RewriteRule .* - [F,L]
</IfModule>
Do not forget to restart your Apache server.
Now your server should return a 403 forbidden HTTP response for URL like those:
- admin
- admin/something
- index.php?q=admin
- index.php?something&q=admin
Notice that you may want to disallow access to update.php too.
Il faut ajouter quelques contrôles supplémentaires
Take: index.php?%26q%3D/admin --pass through
two problems:
* %{QUERY_STRING} contains un-decoded string from the request parameters, so for example the 'as' of 'admin' can be %61, the 'q', the '=' or any url part can still be encoded
* '/admin' is the same as 'admin' for Drupal router
So a final RewriteCond would be:
RewriteCond %{QUERY_STRING} (^|&|%26)(q|%71)(=|%3D)(a|%61)(d|%64)(m|%6D)(i|%69)(n|%6E)(/|%2F|&|%26|$) [NC]
I found no way to get un-encoded query parameters in all apache variables available for mod_rewrite.
forgot the optionnal / in q=/admin
So final RewriteCond is:
RewriteCond %{QUERY_STRING} (^|&|%26)(q|%71)(=|%3D)(/|%2F)?(a|%61)(d|%64)(m|%6D)(i|%69)(n|%6E)(/|%2F|&|%26|$) [NC]
and need to catch q=/////%2F//admin as well
So:
RewriteCond %{QUERY_STRING} (^|&|%26)(q|%71)(=|%3D)(/|%2F)+?(a|%61)(d|%64)(m|%6D)(i|%69)(n|%6E)(/|%2F|&|%26|$) [NC]
Final form, and simplier solution
lol, final form:
RewriteCond %{QUERY_STRING} (^|&|%26|%20)(q|Q|%71|%51)(=|%3D)(/|%2F)+?(a|A|%61|%41)(d|D|%64|%44)(m|M|%6D|%4D)(i|I|%69|%49)(n|N|%6E|%4E)(/|%2F|&|%26|$) [NC]
I wrote a complement to this article, with a simplier solutions and some other rules:
http://www.makina-corpus.org/blog/better-rewriterules-drupal