Http Hobo

Another blog with web-development tips’n’tricks. | About me

2 posts tagged

wordpress

4 steps to secure Wordpress installation on a VPS server

I’m not a huge fan of Worpdress. It’s creators publish security patches and updates so frequently, so every blog owner should hire a system administrator to take care of it. Not that security patches are bad, bad is the fact that so many of them are needed. However, having been watching over my wife’s blog for three years already, I’ve got some recipes on how to secure it and not have a permanent headache about it’s security.

Note: this instruction is for those who knows Linux command line basics.
Another note: My examples are compatible with Ubuntu 16.04.
One more note: Besides Apache + PHP + MySQL I use Nginx as a reverse proxy. It serves static files and provides some functionality which is to be mentioned in this post.

1. Set up correct directory rights

Wordpress has automatic updates for the core and plugins – it looks like a nice feature, but if it works you are in danger. Here is why – that means that your web-server (server software handling requests and sending responses) has rights to modify files in your blog. It means that if somebody will get access to the web-server (through some of countless Wordpress holes), he will be able to modify blog files injecting there malicious code. The only writeable directory for Wordpress should be uploads.

Here is what I do to secure directories:

# 1. Set my user as an owner, and www-data as a group of all the directories and files:
sudo chown george:www-data /my/wordpress/installation -R

# 2. Set directories mode to 755, and files to 644  (read for all, write for owner):
find /my/wordpress/installation -type d -exec chmod 755 {} \;
> find /my/wordpress/installation -type f -exec chmod 644 {} \;

# 3. Set upload directory and it's subfolders mode to 775, and files to 664 (read for all, write for owner and group):
> chmod 775 /my/wordpress/installation/uploads
> find /my/wordpress/installation/uploads -type d -exec chmod 775 {} \;
> find /my/wordpress/installation/uploads -type f -exec chmod 664 {} \;

2. Deny execution of PHP files in directories not supposed to be having PHP files

One of the most commonly used approaches to hack Wordpress I’ve ever seen was attempt to upload some PHP file to uploads directory and run it from there. Besides having correct directory rights, it wouldn’t hurt to deny Apache (or any other web-server) executing PHP files in some certain directories. Here is an example for Apache virtual host:

<Directory ~ "/my/wordpress/installation/(wp-content/uploads)/">
  <Files "*.php">
    Require all denied
  </Files>
</Directory>

Probably there is a way to do this in .htaccess file to make this solution more portable – I haven’t checked.

3. Set up protection against DDoS and bruteforce attacks.

Wordpress’ weak spots are:

  1. wp-login.php page
  2. xmlrpc.php file
    I’ve experienced lots of DDoS attacks on my installation, and logs always show these two files to be a target.

First thing we would do – add another authentication layer to Wordpress. It would be HTTP authorization for wp-login.php file. I use Apache as a web-server and set authorization right in the virtual host:

<Directory /my/wordpress/installation/>
  # Some directory settings

  <Files "wp-login.php">
    AuthType basic
    AuthName "Please enter your username and password"
    AuthUserFile /etc/.htpasswd
    Require valid-user
  </Files>
<Directory>

File /etc/.htpasswd should be created using htpasswd utility.

Now I slow down those who are trying to DDoS or bruteforce my Wordpress. I don’t know how to limit number of requests to a particular file in Apache, but as I sad earlier – I use Nginx which has “Rate limit” functionality, so I added the following settings to it’s configuration files:

# This goes into nginx config (/etc/nginx.conf in my case) into http section. This line will define a zone which will limit requests to 1 per second, and zone's size is 10 Mb.
limit_req_zone $binary_remote_addr zone=mywordpress:10m rate=1r/s;

# This goes into virtual host under server section. All the requests to xmlrpc.php will be handled according to the zone rules, allowing a burst of 5 requests though.
location /xmlrpc.php {
  limit_req zone=mywordpress burst=5;
  proxy_pass http://127.0.0.1:8080;
  include /etc/nginx/proxy_params;
}

location /wp-login.php {
  limit_req zone=mywordpress burst=5;
  proxy_pass http://127.0.0.1:8080;
  include /etc/nginx/proxy_params;
}

What is wrong with xmlrpc.php file? Nothing except it’s commonly used for DDoS attacks. Easier approach would be to just deny access to it, but it’s not a solution in case you want to use some wordpress client. My solution should be better.

4. Addition: protect your phpmyadmin if you have any

I’ve seen tons of access log records showing attempts to find my phpmyadmin – they knocked to /pma, /phpmyadmin, /admin and many other links. So in order to secure it too, I do the following:

  1. Don’t use /phpmyadmin and any other obvious link for PhpMyAdmin. Better use something you can remember, but not related to “php”, “my” and “admin” words, e. g. /blablabla, /ilovemydatabase, /houston.
  2. Bind HTTP authorization to it too. Example is above.

Of course there is more you can do about your wordpress security and safety. I’m not specializing in server administration, but above are recipes which I have been using for some time and having no problems so far. If you have something to add or improve, I would be happy to see you comment.

P.S.: I don’t work with Wordpress a lot. It’s a coincidence having already two posts about Wordpress in my blog. :)

Update 22.11.2017: I thought that PHP files within wp-includes directory are never called directly, and only being included into main script. That’s not correct, for example TinyMCE does a direct call. Thus wp-includes directory should not be blocked in step (2).

2017   security   wordpress

Importing cyrillic Wordpress comments into Disqus

My wife has a blog on Wordpress. She writes in Russian – it’s important to mention (and it’s in the subject). Some time ago I decided to improve the blog a bit, and one of the improvements was moving comments to Disqus. I like Disqus because it makes commenting easier which potentially leads to more comments and discussions. And comments and discussions are good.

I installed Disqus plugin and started to export comments into Disqus. Honestly saying I don’t remember how it ended (it was a while ago), but when I went to Disqus, I found no comments there.

Then I started to try to move comments semi-manually. It means exporting them from Wordpress into .xml file and importing the file into Disqus. It started well – I exported a file successfully. But when I tried to import it into Disqus, page just got reloaded with no message about what is going on. Comments did not appear.

I started to investigate into the issue and found http://import.disqus.com which was a bit more informative on the problem. The error was the following:

XML syntax error: Input is not proper UTF-8, indicate encoding !
Bytes: 0xD0 0xBE 0xD1 0x81, line 51, column 294 (line 51)

If encoding would not be specified and that would be a problem, I would not be writing this post. Surely encoding was indicated. I played with the file really lot -- I was checking it with a hex editor, validating it with XML validators – it all was helpless. I was pretty sure that the problem is connected to cyrillic characters, in fact it might have been, but not directly.

After a long googling, working with the XML file, drinking a lot of tea (I’m a tea drinker, yes) and saying a bunch of “good” words addressed to Disqus importer, I’ve found out a way to get through the issue.

1. Wipe out posts and pages content from the XML

You import comments, not the posts and pages themselves. More contents – more symbols causing troubles. Wipe contents and excerpts, you can even use a regular expression to replace everything between .

<!-- Was: -->
<content:encoded><![CDATA[Привет, тут какой-то текст!]]></content:encoded>
<excerpt:encoded><![CDATA[Тут тоже текст!]]></excerpt:encoded>
<!-- Is: -->
<content:encoded><![CDATA[]]></content:encoded>
<excerpt:encoded><![CDATA[]]></excerpt:encoded>

2. Wipe out all the suspicious punctuation

Regulal expressions would be helpful for this too – I’ve written one to search for everything except commonly used words, digits and punctuation characters. It found me some weird ellipsis, strange dashes and crazy spaces. Removed all of them. You do the same.

3. Do something with the same meaning as shaman dances and hope it helps

Now when you are pretty sure that your file is clean of garbage, it might be imported successfully. Or might be not. Mine was still causing an error, but on different line and column. When I was looking to it, it turned that problem is always caused exactly between CDATA[ opening bracket and first letter of the Cyrillic text. Here is what I did – I added a space there and it worked. When it didn’t helped, I removed the space, tried again. If that didn’t work too – added space again. It’s crazy. I know. Ask Disqus, why. After maximum of three attempts, error was gone and another one appeared until I went through all of them (I had about 150 comments and about 10 errors on this stage).

Finally I was able to import the file. Hope my recipe would be helpful.

P.S. Another small tip which was indirectly mentioned above – don’t forget to move page comments, not posts only. I forgot. Was punched for that. :)

P.P.S. Couple days ago I was importing pages comments which I forgot to import first time. During the import I broke Disqus importer so it started to give me 500 errors. Next day they emailed me saying that there was a bug on their side and they have fixed it. Haven’t checked, but good reaction!

2017   disqus   encoding problems   wordpress