Akismet WordPress plugin is one of the popular plugins for personal WordPress blogs. Nginx is one of the evolving web server, just surpassing Microsoft’s IIS in terms of the usage to be just behind Apache. The ‘bad’ guys always find new ways to exploit a site. Ever since version 2.5.7, Akismet introduced a new .htaccess
file to block direct access to PHP files. The content of that .htaccess file goes like this…
Order Deny,Allow
Deny from all
<FilesMatch "^akismet\.(css|js)$">
Allow from all
The meaning of this code is to allow only CSS and JS files within the Akismet plugin directory (and its sub directories) and block access to everything else. In other terms, it means to block access to PHP files inside Akismet plugin directory and its sub directories, if the request comes from a browser. It basically means the PHP files should only be executed, if accessed from the localhost. It roughly translates into the following code in Nginx…
location ~* /akismet/.*\.php$ {
allow 127.0.0.1;
deny all;
}
I already updated my Github configuration, incorporating the above rules in the restrictions.conf
file. If your host uses Nginx, please sure to ask your host to make sure, the PHP files within Akismet directory are protected. If you’d want even better protection, just deny access to any PHP files within wp-content directory from a browser.
Checking the Nginx rules
If you are unsure about the above protection in your site, you may verify it using curl. Here is the output before enabling the Akismet protection…
curl -I https://www.tinywp.in/wp-content/plugins/akismet/akismet.php
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 21 Mar 2013 11:02:29 GMT
Content-Type: text/html
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: max-age=0, no-cache, no-store
Here is the output after enabling the Akismet protection via Nginx rewrite rules…
curl -I https://www.tinywp.in/wp-content/plugins/akismet/akismet.php
HTTP/1.1 403 Forbidden
Server: nginx
Date: Thu, 21 Mar 2013 11:06:14 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Vary: Accept-Encoding
Pothi,
Thanks for this tip, I’ll give it a try for Akismet.
But splitting hairs (lol), denying all access in Nginx is not the same as allowing only certain files to be accessed.
Some security setups for Apache suggest this in a htaccess file in root folder of wp-content :
[code]
Order deny,allow
Deny from all
<Files ~ ".(xml|css|jpe?g|png|gif|js)$">
Allow from all
</Files>
[/code]
So I can see how one would use the location directive to block all access and allow only the localhost, but the beauty of the htaccess file is that it will allow access to only those file types specified. I just don’t see how this can be done in Nginx, since they do not have a way to have a negative selection (NOT equal to) or a FILES directive.
Would you have some ideas please?
Hi Conrad,
I’ve edited your first comment to include the correct code block. You used the code tag between less than and greater than symbols. WordPress can recognize square brackets, though.
You are right that FILES directive is not available in Nginx. However, negative selection is available. Please see the second example below.
For your use-case, the following may work…
[code]
# untested code
location /wp-content {
#— process static files —#
location ~ "\.(xml|css|jpe?g|png|gif|js)$" {
try_files $uri =404;
expires 1y;
}
#— For all other files —#
# always allow the localhost
allow 127.0.0.1;
# forbid everything else
deny all;
# process PHP files here
}
[/code]
Alternatively, you may use the following…
[code]
# untested code
location ~* "^/wp-content/.*\.(xml|css|jpe?g|png|gif|js)$" {
#— process static files —#
try_files $uri =404;
expires 1y;
}
location !~* "^/wp-content/.*\.(xml|css|jpe?g|png|gif|js)$" {
#— Negative selection —#
# always allow the localhost
allow 127.0.0.1;
# forbid everything else
deny all;
# process PHP files here
}
[/code]
Pothi,
Brilliant! Thanks for the code suggestion, I’m going to try it out in my restrictions.conf – I imagine there will be many surprises lurking when putting this in wp-content.
I think I need to compile a Nginx regex cheat sheet to help me remember …
Hmmm … some code got stripped out …
Order deny, allow
Deny from all
Order deny,allow Deny from all
Allow from all
Drat … again even while using the code markers twice …
So here goes the descriptive way
Order deny,allow Deny from all (smaller than character)Files ~ ".(xml|css|jpe?g|png|gif|js)$"(greater than character) Allow from all (smaller than character)/Files(greater than character)