327 On your server, your WordPress files should be owned by your user account and writable by your username. In general, the proper file permissions are already in place for self-installed versions of WordPress. Most of the time, you will not need to concern yourself with file permissions. Exceptions include situations where you are troubleshooting permission errors, configuring files or directories involved with plugins, or ensuring settings for security purposes. In other words, unless there is a clear and specific need to modify your file permissions, you probably do not need to do so. Even so, when it comes to the security of your site, it is good to make sure that proper permissions settings are in place. Here are a few things to remember: Core WordPress files and directories All core WordPress files should be writable only by your server user account. The default permissions settings for all WordPress files is 0644. The default permissions settings for all WordPress directories (the folders themselves) is 0755. These settings ensure that the core is writable only by the user account and readable by the web server and everyone else. For more information, see the Codex http://digwp.com/u/308. Root HTAccess file The WordPress Codex suggests setting looser permissions for your HTAccess file in order to make it writable by WordPress. The purpose for this involves WordPress’ automatic creation of permalink rules, making it easy for users. A better idea is to leave your HTAccess permissions set at a restrictive level, and then manually add the required permalink directives. For more info, see http://digwp.com/u/278. Theme files Normally, theme files should possess the same permissions as other core WordPress files, however, if you want to use WordPress’ built-in theme editor, you may need to set permissions to make your theme files group-writable. This may not be necessary however, and you should test for editing functionality before changing anything. Check It, don’t Wreck It Before worrying too much about your le permissions, consult your host and ask about their permissions policy. Chances are, you don’t need to change anything, but you should still keep an eye on things. 328 Plugins Although many plugins work fine with WordPress’ default file permissions, there are some that require write access to various files and/or directories. In this case, one of the most common requirements is that the entire wp-content directory be made writable. If so, begin with a permission setting that is as restrictive as possible, such as 755. If this doesn’t provide sufficient privileges on your server, then you may need to use 777, which is not recommended due to reasons explained below. Directories There are a couple of directories that also may need to be writable by WordPress. The first is the wp-content/cache directory, which needs to be writable in order for caching to work properly. The other is the wp-content/uploads directory, which needs to be writable in order for users to upload their content. For files and directories that require additional permissions, keep in mind that it may not be necessary to use 777. Although on some servers, 777 permissions is the only thing that works, there are many cases where a less-permissive setting will do the job. By setting 777 permissions for files or folders, you are opening your site up to attackers who may exploit permissive settings to upload malicious scripts, accessing your database information, and ultimately gaining control of your entire site. For more information on configuring WordPress file permissions, see the “Hardening” section in the WordPress Codex http://digwp.com/u/277. 9.1.4 Disabling Directory Views Another way to increase the security of your WordPress installation is to disable directory views. Many hosts disable directory views on their servers by default, however we want to make sure. When directory views are enabled, any directory that does not include some sort of an index file (e.g., index.html, index.php, etc.) will May I have Permission? When it comes to changing permissions settings, it is considered best practice to use the most restrictive settings possible. Thus, when setting permissions begin with the most restrictive and work your way up until the desired functionality is possible. 329 openly display a list of all included files, thereby exposing them to anyone on the Internet. Here is a typical example of the wp-content folder with directory views enabled: Obviously, this is a huge security risk. If malicious individuals were to gain access to your wp-cong.php file, for example, they could easily access your database and steal sensitive data, destroy your entire site, and otherwise ruin your life. Fortunately, disabling default directory views is drop-dead easy. Simply open your root HTAccess file or Apache configuration file and add the following line, preferably near the top of the file (although it will work anywhere): Options -Indexes Alternately, if HTAccess is not an option, you may prevent directory listings by simply adding a blank index.html or index.php document to each of your WordPress directories. While most versions of WordPress include such “faux” index files by default for the “wp- admin”, “wp-content”, and “wp-includes” directories, there are still many subdirectories that should be protected. After creating pseudo index files in these directories, blank pages will then appear instead of a file listing whenever someone accesses the directories via the Web. Destroy My Site, Please This may be the rst thing an attacker sees before completely destroying your website. 330 9.1.5 Forbid Access to Sensitive Files Protecting the wp-config.php file In addition to disabling directory views, we also want to forbid direct, external access to critical files within the WordPress file system. First and foremost, we want to protect the wp-cong.php file. Each installation of WordPress requires this file in order to connect to the database, set various preferences, and accommodate custom settings. As you can imagine, if some nefarious intruder were to gain access to this file, your entire site – if not the entire server – would be severely compromised. To prevent this sort of tragedy from happening, let’s secure this file with a little HTAccess magic. Here is one way to do it: # SECURE WP-CONFIG.PHP <Files wp\-cong\.php> Order Deny,Allow Deny from all Allow from 123.456.789 </Files> Place that code into your site’s root HTAccess file or Apache configuration file and enjoy immediate protection. This code works by denying all requests for the specified file, wp-cong.php, except for those made from your specific IP address, which is specified in the “Allow from” directive in the fifth line. The IP address in this line should be edited to match that of your own. Note that you may allow access to additional IP addresses or even an entire IP range as follows: Allow access to multiple IP addresses # SECURE WP-CONFIG.PHP <Files wp\-cong\.php> Order Deny,Allow What is my IP Address? If you don’t already know it, the easiest way to determine your IP address is to visit the following URL in your browser: http://digwp.com/u/281 wp-config Tricks For an awesome collection of conguration tricks for your wp-cong.php le, check out these articles at our website: http://digwp.com/u/279 http://digwp.com/u/280 331 Deny from all Allow from 123.456.789 Allow from 456.789.123 Allow from 789.123.456 # additional IP addresses </Files> Allow access to a range of IP addresses # SECURE WP-CONFIG.PHP <Files wp\-cong\.php> Order Deny,Allow Deny from all Allow from 123.456. </Files> To allow multiple IP access, simply replicate and edit as many “Allow from” directives as necessary. To allow a range of IP addresses, use a partial IP address such that any matching IPs will be allowed. Incidentally, allowing a range of IP addresses is a good way to allow access for a dynamic IP address. Protecting the install.php file Used during the WordPress installation process, the install.php file is used to specify your blog title and email address. Once this information is entered, WordPress displays a username and password for the admin account. Unfortunately, during certain database-related issues, WordPress may assume that it has not yet been installed and will load the install.php file. Although this situation is relatively rare, it can compromise your site if not prevented. Fortunately, there are several ways to protect your site: HTAccess Protection for Dynamic IPs If you are working from a dynamically generated IP address, you can edit the Admin-protect code to allow for the changing number. All you need to do is omit the last octet from the IP address and Apache will match any IP that begins with the existing octets. For example, if your dynamic IP ranges from 123.456.789.1 to 123.456.789.255, this code would account for any IP that you may have: <FilesMatch "*.*"> Order Deny,Allow Deny from all Allow from 123.456.789 </FilesMatch> 332 Fix #1: Just nuke it Simply delete the wp-admin/install.php file entirely. It is not needed after installation. Fix #2: HTAccess to the rescue Place the following slice of HTAccess into your site’s web-accessible root directory to prevent access to your install.php file: # PROTECT install.php <Files install.php> Order Allow,Deny Deny from all Satisfy all </Files> Fix #3: Replace it with something safe and useful Replace the insecure version of the file with something secure and informative by following these quick steps: 1. Rename the original install.php to something like “install_DISABLED.php” or whatever. 2. Create a new file named “install.php” and add the following code: <?php // install.php replacement page // http://perishablepress.com/press/2009/05/05/important-security-x-for-wordpress/ ?> <?php header("HTTP/1.1 503 Service Temporarily Unavailable"); ?> <?php header("Status 503 Service Temporarily Unavailable"); ?> <?php header("Retry-After 3600"); // 60 minutes ?> <?php mail("your@email.com", "Database Error", "There is a problem with teh database!"); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Error Establishing Database Connection</title> </head> 333 <body> <img src="images/wordpress-logo.png" /> <h1>Error Establishing Database Connection</h1> <p>We are currently experiencing database issues. Please check back shortly.</p> </body> </html> Once uploaded to your server, this new install.php file will prevent any malicious behavior by serving up a static web page. Now, instead of showing the Installation Page when your database is unavailable, WordPress will display the information shown in this screenshot: In addition to displaying this information to your visitors, the Installation Replacement Page also performs the following actions: • Communicates a 503 (Service Temporarily Unavailable) status code to clients and search engines • Instructs clients and search engines to return after 60 minutes (configurable in third line) • Sends an email informing you of the situation so that you may take action (configurable in fourth line) To use the Replacement Page, don’t forget to specify an email address in the fourth line. You may also change other variables, such as the time duration, email subject, or email message as needed. For complete information on protecting WordPress’ wp-cong.php file, check out the original article at Perishable Press: http://digwp.com/u/282. 334 Protecting the wp-admin directory Once your wp-cong.php file is secure, you should also protect your admin files, which are all conveniently located within the wp-admin directory. Protecting the files in this directory secures a very critical area of your site. The easiest way to do so, is to add the following code to the HTAccess file located in your wp-admin directory (if the HTAccess file does not exist, create it): # SECURE WP-ADMIN FILES <FilesMatch "*.*"> Order Deny,Allow Deny from all Allow from 123.456.789 </FilesMatch> As before, edit the IP address in the “Allow from” line to match your own. Alternately, you may use this code instead (also placed into the wp-admin HTAccess file): # SECURE WP-ADMIN FILES <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REMOTE_ADDR} !^123\.456\.789 RewriteRule ^(.*)$ - [F,L] </IfModule> This second method requires Apache’s mod_rewrite module and works by denying access to any IP that is not your own. Thus, as before, you will need to edit the IP address accordingly. Once in place, this code will deny Limit Login Attempts Limit the number of times a user can try different passwords for your site with the Login Lockdown plugin http://digwp.com/u/7. By setting some maximum number of login attempts, you greatly reduce the chance that an attacker will gain access by guessing your password. After the max number of attempts, the user is locked out for a specified period of time. All settings easily controlled via Admin panel. Remove the Login Error Message Another tip for improving security is prevent WordPress from displaying the default error message on the Login Page. Invalid login attempts are met with a message that informs the user of the problem with their login credentials. Thus, if an attacker were to guess your username, the login error would provide confirmation and enable the attacker to focus on your password. Fortunately, preventing the login error message is as simple as adding the following line to your functions.php file: add_lter('login_errors',create_ function('$a', "return null;")); 335 access – to everyone except for you – to all files in your wp-admin directory by returning a 403 Forbidden error message. Note that you can choose to redirect denied requests to the URL of your choice by replacing the last line with this: RewriteRule ^(.*)$ http://domain.tld/ [R,L] Simply edit the URL to whatever you wish. Note that blocking your site’s wp-admin directory with HTAccess may produce unintended results. Specifically, if there are scripts or plugins that need to access your Admin area or its files, they will be prevented from doing so if your admin is locked down. One specific example that comes to mind is the “unsubscribe” feature of the Subscribe to Comments plugin. When a subscriber wants to manage their subscriptions, they need access to Admin files to do so. Protecting the Admin Login Page The WordPress Login Page is a frequent topic of discussion where security is concerned. As the virtual “door” to your Admin area, it is important to secure the page as strongly as possible. Here are some effective strategies for doing so: • Choose a strong password Choosing a super-strong password is your site’s first line of defense. Avoid simple words and phrases, and use a good mix of numbers and upper- and lowercase letters. Additionally, with WordPress, you may use other characters such as underscores and dashes to further confound your password. If you need help, do a quick Google search for “online password generators.” There are many available. • Change your password often Once you have chosen a strong password, use it for awhile and The Easy Way to Password Protect the wp-admin Directory If you would rather not bother with the HTAccess method, you may want to try the AskApache Password Protect plugin http://digwp.com/ u/5. This plugin will encrypt your password, create the .htpasswd file, and set the proper file permissions. Another good plugin for locking down your wp-admin directory is WP-Adminprotection http://digwp. com/u/6, which allows only specified IPs access. Check it out. Alternately, if you would rather not bog down your site with another plugin, you may want to check with your web host. You may be able to create password-protected directories with a few clicks of the mouse from your server control panel. For example, most cPanel implementations make this easy to do. 336 then change it to something new. Even if you simply change a few characters to keep it easy to remember, it is best to do so to ensure optimal password security. • Block access to the Login Page Although blocking access is an excellent way to secure your Login Page, doing so will also prevent normal visitors from registering with your site. The reason for this involves the way the Login Page and the Register Page are served from the same PHP file. The URL for the Register page looks something like this: http://domain.tld/blog/wp-login.php?action=register …which is calling the wp-login.php file and targeting the registration portion of it via the “action=register” query string. Thus, we can secure our site by blocking access to the Login Page, but in doing so, the Register Page will also be unavailable. Even so, if you are not allowing people to register with your site, locking down the Login Page is a strong security measure. To do so, add the following directives to the HTAccess file in your wp-admin directory: # PROTECT WP-LOGIN.PHP <Files wp\-login\.php> Order Deny,Allow Deny from all Allow from 123.456.789.0 </Files> As in previous examples, simply edit the IP address to match your own. You may also allow additional IPs to access your Login Page by emulating the “Allow from” directive as many times as is necessary. Once in place, this method will allow only the listed IP address(es) to Emergency Password Change If you ever find yourself in a situation where you can’t send or receive email but need to change the password of your admin-level account, you can do so easily via the database and phpMyAdmin: 1) Browse the “wp_users” table and click to edit the account name for which you would like to change the password. 2) In the “user_pass” field, you will see the encrypted version of your current password, which will look something like this: “%tH1sw0uldb3Y0ur3n cRYP73dpa$$w0rd”. Replace this existing value with the plain-text version of your new password (e.g., “n3w_pa$$w0rd”). 3) Finally, select the “MD5” option from the dropdown box (just to the left of the text field) and save your changes by clicking “Go!” This will tell phpMyAdmin to encrypt your plain-text password with the requisite MD5 hash. Voila! It’s that easy. Keep in mind that MD5 is designed for one-way encryption – you can use this method to encrypt new passwords, but you will not be able to decrypt existing passwords. It’s strictly a one-way street. We recently posted an article on this topic at the Digging into WordPress website. In it, you will find everything you need to know about changing your password with WordPress in virtually any situation: http://digwp.com/u/283 . document to each of your WordPress directories. While most versions of WordPress include such “faux” index files by default for the “wp- admin”, “wp-content”, and “wp-includes” directories, there. install.php replacement page // http://perishablepress.com/press/2009/05/05/important-security-x-for -wordpress/ ?> <?php header("HTTP/1.1 503 Service Temporarily Unavailable");. permissions as other core WordPress files, however, if you want to use WordPress built-in theme editor, you may need to set permissions to make your theme files group-writable. This may not be