Additional WordPress Hardening for Subfolder Instances

WordPress is content management system (CMS) software that is made to be simple for people to use. It’s very popular is and probably best for blogs, but is used for all kinds of websites—from hobbyist to professional. Even ChadSpace uses WordPress! (At least until ChadPress is finished, which is going to be totally awesome.)

Unfortunately, the above mentioned qualities—that is, “software” and “simple”—do not always complement each other so well. Sometimes, this particular combination of development priorities creates opportunities for end-users to screw themselves. This is especially true whenever necessarily complex tasks are attempted to be made simpler than they really are. Unsurprisingly, WordPress sites, which are “simple” to set up, are highly susceptible to attacks, as detailed in many articles online icon-external-link-12x12 icon-search-12x12 .

One of the scariest things about WordPress is that there exists a file called wp-config.php that contains a username and password for the associated SQL database, and it is located in the servable space of a website. The password is given in plaintext—that is, unhashed and unencrypted—and reads clear as day for anyone with access. This is utterly absurd, and serves as a huge red flag for any self-respecting technologist.

Assuming your server is running PHP, and that it is configured correctly, anyone attempting to view the contents of wp-config.php in their web browser will be treated to a blank document. However, technology frequently sucks icon-external-link-12x12 and a routine system update procedure can kill PHP but leave Apache running, exposing a WordPress site’s database password to the entire world.

There are additional precautions that can and should be taken to keep the data in this file off limits. If you are hosting your site with Apache Web Server, an additional setting added to the main .htaccess configuration file can deny all external access. This works, but still isn’t good enough.

WordPress also allows end-users to move the wp-config.php file up one directory, which is presumably outside of a website’s servable space, and the software will still find the file in its new and more protected location without any additional configuration. This is the right idea, but doesn’t work for WordPress sites that are installed in the subfolder of a domain—like ChadSpace, for instance.

So don’t be a shithead: protect the database password for realsies. This can be done by making some rather quick changes to the wp-config.php file.

Step 01) Create four new files, all of which are located two directories up—or more, if necessary—from where WordPress is located (adjacent to the public_html folder if you are using a conventional Apache setup):

<sitename>-wordpress-db-config.php
<sitename>-wordpress-env-config.php
<sitename>-wordpress-plugins-config.php
<sitename>-wordpress-keys-config.php

Where <sitename> is… yeah, nevermind. ChadSpace is hosted on the unwisdom.org domain and so its files—chadspace-wordpress-db-config.php, chadspace-wordpress-env-config.php, etc.—are adjacent to the public_html folder that represents Apache’s servable space for unwisdom.org.

Step 02) Start gutting your existing wp-config.php file and put the code in the relevant files that were just created. For ChadSpace, this looks like the following:

chadspace-wordpress-db-config.php

<?php
// ** MySQL settings - You can get this info from your web host ** //

/** The name of the database for WordPress */
define('DB_NAME', 'chadspace');

/** MySQL database username */
define('DB_USER', 'chadspace');

/** MySQL database password */
define('DB_PASSWORD', 'superSECRETdatabasePASSWORDthatNOBODYknows!!!');

/** MySQL hostname */
define('DB_HOST', 'localhost');

/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');

/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');

chadspace-wordpress-env-config.php

<?php
/** The maximum file upload size. */
define('WP_MEMORY_LIMIT', '64M');

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each a unique
 * prefix. Only numbers, letters, and underscores please!
 */
$table_prefix  = 'wp_';

/**
 * WordPress Localized Language, defaults to English.
 *
 * Change this to localize WordPress. A corresponding MO file for the chosen
 * language must be installed to wp-content/languages. For example, install
 * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German
 * language support.
 */
define('WPLANG', '');

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 */
define('WP_DEBUG', false);

/** Override default site URL values in database (for site migration) */
define('WP_HOME','http://unwisdom.org/chadspace/');
define('WP_SITEURL','http://unwisdom.org/chadspace/');

chadspace-wordpress-plugins-config.php

<?php
//define('WP_CACHE', true); //Added by WP-Cache Manager
define( 'WPCACHEHOME', '/var/www/unwisdom.org/public_html/chadspace/wp-content/plugins/wp-super-cache/' ); //Added by WP-Cache Manager

chadspace-wordpress-keys-config.php

<?php
/**#@+
 * Authentication Unique Keys and Salts.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define('AUTH_KEY',         'c_xztwa)O^A8lWeyGVJC(J!HHE8h(Rj\`e$i9fXP!r_RO|6fz=@r!G@z1P9ufDoxzb:VEF');
define('SECURE_AUTH_KEY',  '7SbkH2A1NeH-6XNgu;a^PwYvE*VrYmgvy5Z90$#eR~U|9tHpkUbT4_?$4JGj6Or@Gg7RHW|df');
define('LOGGED_IN_KEY',    '-F/mR?mj_(uOb$uJp@6^WvNN?aKF44J!p~:eUrM13zJ0G/Zr0T\`d~af3vft)anW2PB!ZY');
define('NONCE_KEY',        '_snMEr2=KxSlQ;m~^gVFfTea~p9m4hF|$k5x58z?eLIsOpZ_MGn1kHw(b^9rStm#eu0');
define('AUTH_SALT',        'jL\`PEQtP$0G3hJEfh;ai(YO5=C8hww$bC3P=^eM1db\`u|\`c*xZ7-8bS7tQ5S(3a/lr');
define('SECURE_AUTH_SALT', '!J=_ZYYL5mW|VUQ@SNy#eyb0fI\`Nu|CZ7oG-ql4c~tO!0sS6H5ZQFC45-(s0Jjx\`7viHt|^lrO0|w');
define('LOGGED_IN_SALT',   'HtW(RyWtVrgQ$_?Fdy|ej*pEz@y52jtr|moTACHc-XWYP-OGC@UQ59!#G-3db5=M#T:2;jeED)IITa((Ts');
define('NONCE_SALT',       '(Phh\`)~QI@mzx*/n:F?IgB/XnZNjarXTUXj_1T6e2^CgnP^YvjMs5iVKe!~QpblLE-');
/**#@-*/

Step 03) Update and slightly restructure your wp-config.php file. This involves moving the definition for ABSPATH to be the first chunk of code that is executed; executing the four newly created files with include function invocations; and leaving the require_once function call for the wp-settings.php file as the final executed line.

wp-config.php

<?php
/**
 * The base configurations of the WordPress.
 *
 * This file has the following configurations: MySQL settings, Table Prefix,
 * Secret Keys, WordPress Language, and ABSPATH. You can find more information
 * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing
 * wp-config.php} Codex page. You can get the MySQL settings from your web host.
 *
 * This file is used by the wp-config.php creation script during the
 * installation. You don't have to use the web site, you can just copy this file
 * to "wp-config.php" and fill in the values.
 *
 * @package WordPress
 */

/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');

include(ABSPATH . '/' . '../../chadspace-wordpress-db-config.php');
include(ABSPATH . '/' . '../../chadspace-wordpress-plugins-config.php');
include(ABSPATH . '/' . '../../chadspace-wordpress-env-config.php');
include(ABSPATH . '/' . '../../chadspace-wordpress-keys-config.php');

/* That's all, stop editing! Happy blogging. */

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

Configuring wp-config.php in this way does a couple of important things: it ensures that the database password can never be accessed through web server routines, and it abstracts away icon-external-link-12x12 the directory structure of your web server. This means that if someone is somehow able to view the contents of this file, it will not betray any sensitive information about the host server and how it is configured.

All that said, even if a WordPress database password is exposed, it doesn’t guarantee that an attacker will be able to gain access to the database server. But is it really okay that so many WordPress webmasters are taking this unnecessary risk? Compromised computer security is just a game of probability: out of one million WordPress sites, how many experience server trouble from time to time or don’t understand how to set file permissions correctly? Many of these people inadvertently leave their database passwords exposed to the world. Of these, how many are using this same password somewhere else, like the associated WordPress admin account… or an email account… or an Xbox Live account… or an online banking account?

Snowplow Programming

Matrix Multiply Parallelization icon-external-link-12x12 was the second project for the Summer 2013 semester class CS61C: Great Ideas in Computer Architecture (Machine Structures) icon-external-link-12x12 at UC Berkeley. This was the first time that people were allowed to work in pairs, as all previous assignments were intended for individual completion. The project itself was broken up into two parts that were to be submitted separately. Part one had two objectives: write code that efficiently computes matrices of varying sizes, and write code that is optimized for computation of a base-case 36×36 matrix.

The person with whom I had been studying for homework assignments neglected to tell me that she paired up with another classmate; I didn’t find out that I needed to get a new partner until the day we were supposed to submit our pairings to the teacher’s assistants. As a result, I ended up with a very questionable fellow who didn’t seem at all like the type of student I expected to find at UC Berkeley. Even more interesting was that I met many more like him in the days following our introduction.

I elected to write the code for handling matrices of varying sizes and suggested that he handle the base case. I did this for two reasons: 01) I saw an opportunity to apply what I had learned in my Linear Algebra studies to a challenging programming exercise, and 02) I didn’t at all feel comfortable letting him take responsibility for this more delicate part of the program. During the next week, we hardly worked together, which was one of the most unusual mixtures of relief and disappointment that I have ever experienced in my life.

As I was finishing up our project submission icon-external-link-12x12 , I decided to check in with my partner to see how his work was coming along. I was not very surprised to discover that he figured out a way to get everything done and that our program’s performance for the base case was at the top of the scale. Fortunately we weren’t nabbed for any funny business, but we should have been. I would be willing to bet that we got full credit on part one of the project, but honestly, I never bothered to check.

It’s interesting to note that my part of the program was only worth 20 points (~36.4%), while my partner’s part was worth 35 points (~64.6%).

8,760,000 Work Hours

8760000-work-hours-000000-formatted

According to a statement in the book The Well-Grounded Java Developer icon-external-link-12x12 icon-search-12x12, the Java Virtual Machine—which is that incredibly nifty piece of software that allows applications written in the Java programming language and others icon-external-link-12x12 to run on many different types of operating systems, such as Windows, Mac OSX, Linux, etc.—represents approximately “1,000 person-years of effort”. The book was published in mid-2012, which was more than three years ago now, so that number would already be significantly higher.

Let’s do some simple arithmetic:

y = ( number of years )
d = ( number of days per year )
h = ( number of hours per day )
t = ( total number of hours )

t = y * d * h

y = 10 yr
d = 365 day/yr
h = 24 hr/day

t = ( 10 yr ) * ( 365 day/yr ) * ( 24 hr/day )

t = 8,760,000 hr

Assuming that a standard year’s worth of work is comprised of 2,000 hours of labor—and I feel obliged to point out that this is a number at which some people would scoff—it would take one person 4,380 years to match the amount of time that was committed to this technology back when those words were put into print.

On a somewhat related note, I find it interesting that the authors chose the term “person-years”, as if the fellows on the Java team are something other than human. Perhaps I’m reading into this too much, but it may suggest that the Java Virtual Machine was made by aliens… or dogs… or maybe very intelligent hamsters?

From Bango-Bongo-Bingo to Led Zeppelin

It’s interesting to me the ways in which Computer Science exams attempt to deceive students. The trick that sometimes gets me is the unnecessary-answer-inversion modification: start out with a mostly straightforward question and make the correct answer the opposite of what would be expected.

from-bango-bongo-bingo-to-led-zeppelin-000001-formatted

The example above contains a second artificial layer of difficulty through the use of nonsense words in an inheritance hierarchy. After reading the code, any reasonable person would question the name Bango and how it relates to a Bingo and Bongo. It’s at this point that one must accept the game that’s being played between the educator and the learner. Sadly, induced cognitive stutterings are one particular result of the malformed educational transaction that is occurring.

Another trick that works on me 100% of the time is the unnecessary-details-about-awesome-rock-and-roll-band modification:

from-bango-bongo-bingo-to-led-zeppelin-000000-formatted

In this case, I started thinking about how I would much rather be playing bongos along to Houses of the Holy icon-external-link-12x12 icon-search-12x12 than taking this stupid test.