This article is obsolete. The instructions given will not work with current MediaWiki versions. Please refer to the updated version of this article.

MediaWiki is the software behind Wikipedia, but you can use it to create your own special-purpose sites. I've used it at work to build an internal company knowledge base, and I'm using it at home to make a Wiki for the fictional world of a roleplaying game I'm in.

It's a pretty polished software package, but out of the box it tends to assume that you are creating something like Wikipedia that is visible to (and editable by) the whole wide world. If that's not what you want, it requires some tuning, which I'll describe in detail after the jump.

Why MediaWiki?

An obvious question is, if the MediaWiki software needs tweaking to do what I want, why do I use it and not some other software? A few reasons:

  • It's just a Wiki. I've tried doing similar things with other packages (such as Tiki Wiki), and ended up wasting lots of time fighting with or trying to turn off features I didn't want or need. A CMS or blogging package or groupware suite are great if you need those things, but they all tend to assume a certain workflow and division of responsibility. If you are just trying to create a Wiki, you'll waste time swimming against the current.
  • The Wikitext markup language is reasonably intuitive (simple things are simple, and new users can start contributing right away) but still powerful enough to create complex pages. It's incredibly well-tested, and doesn't flake out in odd corner-cases. There's a huge volume of example pages out there.
  • It's decently fast even on a modest computer, without resorting to esoteric fastcgi and caching tricks.
  • There are lots of useful plugins available.
  • Because of the huge user base, most "How do I...?" questions are answered with a simple web search.

Prerequisites

The remainder of this article will assume that you're starting with a fresh install of MediaWiki, and have an admin user set up (and know its password). You'll also need the ability to edit files under the MediaWiki install tree (via command-line access or FTP or any other means).

While the methods I describe should be reasonably general, future releases may involve different ways of doing things. The process described below was tested and is known to work with the following software versions:

  • MediaWiki 1.16.0 1.18.2
  • PHP 5.3.3 (cgi-fcgi) 5.3.6-13ubuntu3.6
  • MySQL 4.1.20 5.1.61
  • Perl 5.8.8 5.12.4
  • Apache 2.2.8 2.2.20

Restricting Access to Registered Users Only

The first step in creating a private Wiki (and one which is well-documented elsewhere) is to make it so that only logged-in users can view or edit pages (other than the login page), and so that only sysops can create new accounts.

Edit your LocalSettings.php to include the following lines (I made all manual additions at the bottom of the file):

# Disable reading by anonymous users
$wgGroupPermissions['*']['read'] = false;

# Disable anonymous editing
$wgGroupPermissions['*']['edit'] = false;

# Prevent new user registrations except by sysops
$wgGroupPermissions['*']['createaccount'] = false;

Disabling "Remember Passwords" in MediaWiki

That's a good start, but there's still a big problem: the "Remember my login on this computer" checkbox on the the login form. If the user checks this (and users, being users, will check it), it stores a password-equivalent token in a cookie on the user's browser. That means that anyone with access to the user's computer (which, for 'doze boxes, is likely the whole Internet) can use your Wiki as that user.

Having the browser automatically log the user in isn't quite the same as having no password at all, but it's pretty bad. It's giving up a huge degree of security for a very minor convenience. If what you're protecting has any value at all, you don't want it.

So how to get rid of this misfeature? Add the following to your LocalSettings.php:

# Disable "remember password" on login page:
require_once('extensions/NoRememberAuthPlugin.php');
$wgAuth = new NoRememberAuthPlugin();

# Disable "remember password" on user preferences page:
$wgHooks['GetPreferences'][] = 'NoRememberPrefHook';
function NoRememberPrefHook($user, &$preferences) {
    unset($preferences['rememberpassword']);
    return true;
}

Add a file extensions/NoRememberAuthPlugin.php containing the following:

<?php
require_once ('includes/AuthPlugin.php');
class NoRememberAuthPlugin extends AuthPlugin {
   function modifyUITemplate(& $template) {
      //disable 'remember me' box
      $template->set('remember', false);
      $template->set('canremember', false);
   }
}
?>

Notice that we also keep users from turning "remember me" back on in their preferences, and disable it (at the next login) for any users who had it enabled before we made the change.

Also notice that all the modifications so far have been edits to LocalSettings.php and the creation of a new extension. These are all things that should survive a MediaWiki upgrade intact.

Disabling "Remember Passwords" in the Browser

Now that we've stopped the MediaWiki software from sabotaging its own security, our next challenge is the user's web browser. The browser may have has its own separate "remember password" (aka "form fill in" or "wallet") feature, and some users leave that turned on. We can't really check for or enforce a particular setting; there's no way, from the server end, to tell if the credentials were supplied via keyboard or autocompleted by the browser.

One approach we could use (and which I did use, on a previous project) is to randomize the URL of the login page or the field names or both. The browser can still "remember" the password, but won't know to use it on the next login. On a scale from good to bad, this is bad: password-equivalent data is still sitting on the user's disk. It's also not easy (for me) to implement within MediaWiki.

Fortunately, there is another option: we can put a hint in the page source to tell the browser to turn off "remember password" for a particular form. We do this by adding an autocomplete attribute to the form element, with a value of off.

There are a couple disadvantages to this approach: First, autocomplete="off" is not part of any web standard (though it is supported in both Gecko-engine browsers like Firefox and in IE). Second, I didn't see any obvious way to add it to the necessary places using LocalSettings.php or an extension.

There are two places is one place where the form-fill-in behavior is problematic: on the user login screen, and on the screen where the user can change his password. For the user login screen, edit the file includes/templates/Userlogin.php, find the form with name="userlogin" and add the autocomplete="off" attribute. (You may want to back up the file first.) Here is part of a context diff from my installation:

-<form name="userlogin" method="post" action="<?php $this->text('action') ?>">
+<form name="userlogin" method="post" action="<?php $this->text('action') ?>" autocomplete="off">

When you are testing this (and you should test it), remember to turn the "remember password" feature of your browser back off when you are done.

Enforcing Password Quality

Another weak link in the chain is password quality. People tend to pick bad, easily-guessed passwords. While we would like for them to not do that, it requires a delicate balancing act. If the password rules are too strict, users won't be able to pick passwords they can remember, and will end up writing them down (which is worse in some ways than picking a weak password). If we pick really silly rules, it can dramatically narrow the search space for an attacker trying to find passwords by brute force.

On the other hand, using password quality rules has another benefit beyond making sure passwords are harder to guess: it helps ensure that users don't use the same password for multiple unrelated sites.

There are MediaWiki extensions (like SafeCreate) which enforce password rules, but I didn't really like the way any of them work (and my PHP skills aren't very strong). So, instead I came up with a way to call an arbitrary, external program to test potential new passwords. Here is the code (to be added to LocalSettings.php):

# Enforce strong passwords when password is changed:
$wgHooks['PrefsPasswordAudit'][] = 'ChkStrongPassword';
function ChkStrongPassword($user, $newPass, $error) {
   $output = array();

   if($error !== 'success') { return true; }
   putenv("CHKPASS=$newPass");
   exec("/home/mywikiuser/bin/chkpass", $output, $rtn);
   putenv("CHKPASS");
   if($rtn) {
      throw new PasswordError(implode($output));
   }

   return true;
}

We are calling the program /home/mywikiuser/bin/chkpass to check passwords. This program expects the environment variable CHKPASS to be set to the potential new password. (We pass it in via the environment rather than the command line because other interactive users on the server may be able to see the command-line options of running jobs. I used an environment variable rather than stdin because it appeared easier to do in PHP.)

If the password meets our requirements, the chkpass program should return success (exit status 0) and emit no output. If the password fails to meet requirements, chkpass should return failure (exit status non-0) and emit to stdout a human-readable text description of what is wrong.

Here is a link to my sample implementation: chkpass (1397B Perl script)

Requiring HTTPS

Even if users have to authenticate using strong passwords that they've committed to memory, that accomplishes little if those passwords are flying over the 'net in cleartext -- or if the content protected by those passwords is sent in the clear.

Fortunately, there is a relatively simple solution: make sure we use HTTPS for every transaction. If you're using Apache 2.x, this can be accomplished  by putting something like the following in the .htaccess file for your Wiki:

# If HTTPS, require a strong cipher
SSLOptions           +StrictRequire
SSLRequire           %{SSL_CIPHER_USEKEYSIZE} >= 128

# Insist on HTTPS always
RewriteEngine        on
RewriteCond          %{HTTPS} !=on
RewriteRule          .* - [F]

With the above in place, any access attempt using plain old HTTP will be met with a "403 Forbidden" error. Note that you'll need an SSL certificate to use HTTPS, either self-signed or certified by a CA. If the former, users will need to manually establish the chain of trust for your cert the first time they access your site.

[Edited 2012-04-20 by DGH to work with MediaWiki 1.18.2 install on Ubuntu 11.10 Server]