Public:MediaWiki security
From LiquidWiki
This article is intended to be a beginning-to-end guide for setting up a basic form of namespace-based security for a MediaWiki installation, without the usage of any extensions or patches. Content will be private from anonymous visitors unless it is intentionally publicized.
Background
This guide is based upon my experience setting up namespace-based security on a v1.8.2 MediaWiki installation. MediaWiki's default low-security open setup is based around what the MediaWiki community popularly refers to as the 'wiki spirit'. This concept of openness and freedom is implemented by giving permission to read and edit all content to all visitors. No information is private. Information is protected from corruption through the practice of vigilance over recent changes. When information is changed for the worse, an individual would amend it either via further editing or by reverting the text to a previous version. For your implementation you may find this to be manpower-intensive, and you may choose instead to utilize a different wiki software or otherwise implement security policies similar to those that I have employed here in my own installation: LiquidWiki
LiquidWiki is primarily a personal reference where I compile ideas and insights using MediaWiki's simple and convenient system for producing hyperlinked content. I've found that the interlinked articles do well for modeling my own ideas and experiences, and it makes for a more sensible publishing system than the more linear blog system, even with the addition of tagging. Furthermore, some of the ideas that I write up in here are seeds for personal projects, which I intend to protect as my own private IP. I have a small circle of trusted friends who have been granted accounts with access, but anonymous internet users are normally locked out.
Goals
This guide's purpose is to create a professional MediaWiki installation, which provides the anonymous visitor with knowledge of the site's nature and purpose, but limiting access to content that was intentionally opened to the public. We will create this secured MediaWiki installation first by locking it down completely, and then opening up sections by whitelisting system pages and creating a namespace for publicized content articles.
Namespaces explained
In general, a namespace is an abstract container providing context for the items that it holds, such as names, technical terms, words, etc. A namespace allows disambiguation of items that have the same name by placing each in its own namespace. [1]
In MediaWiki, a namespace is a "container" for content pages. Namespaces are denoted by a prefix before the article name, with the exception of the main namespace which has no prefix.
For example, you may have an article named "Thingies" located in the main namespace, where it would be titled "Thingies". The page for wiki editors to discuss the article is automatically created in the "Talk" namespace, and is titled "Talk:Thingies". A user may have coincidentally chosen to create an account with a username of "Thingies" and a page would have automatically been generated in the "User" namespace, and would be titled "User:Thingies".
Steps to security
Step 1: Pre-requisites
These steps are based upon the assumption that you have already successfully installed a recent version of MediaWiki and have successfully set up an administrative account for yourself. You'll also need to know how to access and edit two files in your MediaWiki installation: LocalSettings.php and includes/Title.php These files are NOT MediaWiki articles and are NOT accessible from within your wiki. You need to be able to browse and edit the files that were installed to your server to create your MediaWiki installation
If you don't know how to do these things, I suggest referring to MediaWiki.org or meta.Wikimedia.org for MediaWiki questions. For hosting issues, please refer to your hosting service or whoever set up your server. If you're having problems with locating or editing the files in question, you may need to refer to a Linux reference. I will reiterate that LocalSettings.php is located in the top level of your wiki installation, whereas Title.php is in the includes directory.
Step 2: Post-install lockdown
The first real step is to lock out anonymous users. This is done by editing your LocalSettings.php file. We'll go straight to the end of that file and add the following lines of text:
# security additions $wgWhitelistRead = array( "Main Page", "Special:Userlogin", "-", "MediaWiki:Monobook.css" ); $wgGroupPermissions['*']['edit'] = false; $wgGroupPermissions['*']['read'] = false; $wgGroupPermissions['*']['createaccount'] = false;
We'll dissect this line-by-line. The line that starts with the # symbol denotes that it is a comment, and has no function aside from marking the beginning of our additions. Ignore it, or call it line number zero if you must.
The real first line establishes the whitelist of pages that are always available to visitors regardless of security settings. This basic selection here is drawn directly from here. The pages are named using their internal wiki names including namespaces. The first two are the absolute basics: your main page and the login page. If you don't include the login page here, then you cannot log in. The main page is not functionally necessary, but it is good design to leave out a welcome-mat. The dash is not something that I have been able to find an explanation for, and is taken directly from the page linked above. The MonoBook page is necessary for including any alterations you may have added to the default design via the internal wiki page (see here for an example). If your MediaWiki install uses a different default style, you may need to input a different page name here.
The second line contains the first set of group permission changes. To understand the code here, it is important to first understand a few things about MediaWiki group permissions. A special 'read-only' file called includes/DefaultSettings.php assigns default rights for MediaWiki groups using commands just like this one. Changes made to a group's rights in LocalSettings.php replace the defaults, but some rules can override others. In the second line of code, the asterick represents all users, including anonymous ones. The ability to edit pages or "edit" is the type of rights being altered. "false" indicates that the right is denied, whereas granting the right would require a "true" here. When read explicitly, this line attempts to disable editing rights for all users, but don't worry, this will only apply to anonymous users. The group "user", which represents all logged-in users, has been explicitly given the right to "edit" by includes/DefaultSettings.php Although "user" (logged-in users) are technically a subset of "*" (all users including anonymous), they are still allowed to edit because rules for "user" have higher priority than "*". To summarize, this line denies anonymous users the ability to edit your wiki, but does not remove the right from logged-in users. If you wish to remove that right, you would have to do so explicitly via another rule.
The third line disables reading rights for anonymous users. Note that although anonymous users are being blocked by this line here, the whitelist supersedes this command so that anonymous users can still access the pages explicitly listed in the whitelist. In other words, the whitelist always applies, no matter what happens otherwise. Like the rule above, this only applies to anonymous users, as includes/DefaultSettings.php explicitly grants reading rights to logged-in users.
The fourth line prevents anonymous users from creating accounts. This rule is unlike the two previous, in that it will also deny the average "user" from creating accounts also as they have no explicit rule granting them this right. After this rule, only "sysop" level users are provided account creation privileges. After this is set, all accounts for new users have to be created for them by members of the sysop group. It's a necessary step in order seal what would be a blatant security hole. Constraining account creation shouldn't create too much extra overhead, as rate of account creation isn't usually an issue with wiki management, especially in a more private MediaWiki install like this one.
Step 3: (Optional) Some legacy settings
The following lines are of low importance and almost no security significance, as we've already locked down most access for anonymous users. One of these duplicates functionality in the general block and the second just removes a dead link for anonymous users.
$wgDisableAnonTalk = true; $wgShowIPinHeader = false;
The first line prevents anonymous users from utilizing talk pages. It is here as an artifact from an earlier security schema, utilizing the page restriction patch for MediaWiki versions earlier than 1.7. Currently it is redundant with the general prevention. I have not been able to confirm whether this overrides whitepages. It does not remove the discussion tab.
The second line prevents display of the IP address that shows in the user bar for anonymous users. Although the users were already locked out of accessing these pages, this removes the option for accessing these pages entirely. Again, not entirely necessary, but it does remove an inoperative link.
Step 4: (Optional) Adding wiki-specific whitepages for your footer
This is an optional step which involves whitelisting a few more system-generated pages to your $wgWhitelistRead entry. These are not necessary from a security perspective, but they do offer important information about your individual wiki. These pages are built-in to MediaWiki for establishing your site's identity and policies and are automatically linked by the default MediaWiki footer which appears on every page of your wiki. You will need to fill in the content for these pages yourself, as the installation only generates place-holders. Although not critical to functionality, if you're looking to give your MediaWiki installation a professional treatment, you'll definately want to have these present and available.
This step will differ depending on what you entered for the name of your wiki. If you're uncertain, you can easily confirm this setting by checking your footer, where you'll see the "About X" link, where X is the name of your wiki. In the following examples, I'll be using the name of my wiki: LiquidWiki. Substitute the name of your own wiki whre needed and then add the following to your $wgWhitelistRead: "LiquidWiki:Privacy policy", "LiquidWiki:About", "LiquidWiki:General disclaimer". This will unlock the pages linked in your footer so that they will be accessible by anonymous users. The final $wgWhiteListRead line should resemble the below:
- $wgWhitelistRead = array( "Main Page", "Special:Userlogin", "-", "MediaWiki:Monobook.css", "LiquidWiki:Privacy policy", "LiquidWiki:About", "LiquidWiki:General disclaimer" );
Step 5: Creating a new namespace
Now your MediaWiki installation is locked down and cannot be accessed by anonymous users, except for pages that you have added to your whitelist. Unfortunately the whitelist quite rapidly becomes cumbersome to deal with, especially because the title must be entered exactly. Keeping the titles perfect in a separate system file is a big problem when wiki pages can and will be retitled on the fly. A remedy is available, through the usage of namespaces. Using a custom namespace can allow you to openly share any articles that you move to the namespace. As long as the article remains within the namespace, the title can be changed freely. This step will create the new namespace.
First though, a preventative warning: Do not attempt to assign articles to a namespace before creating it! If you try moving articles to your namespace before editing your LocalSettings.php to create the namespace, you should consult the information here for fixing the pages as they won't actually be in the namespace.
In order to create a new namespace, a few more lines will have to be added to the end of your LocalSettings.php For my examples, I will be using "Public" for the name of the new namespace. You can rename it to whatever you see fit, but I recommend keeping it simple.
# extra namespace $wgExtraNamespaces[100] = "Public"; $wgExtraNamespaces[101] = "Public_talk"; $wgContentNamespaces[] = 100;
The first line is simply a comment, denoting the section.
The second line creates the namespace, while the third line creates the corresponding discussion namespace. To quote an excellent passage from "Manual:Using custom namespaces" at MediaWiki.org:
- Note the use of the constant 100 in defining the namespace. All namespaces require a numerical index; for custom namespaces, these start at 100. Another point to remember is that an even namespace index denotes a content namespace, whereas an odd index denotes a discussion namespace. It is usual to define a discussion namespace with each custom namespace
If you wish to add multiple custom namespaces, you will need to take careful notice of the numbers to which the namespace is assigned. This is important because MediaWiki internally identifies your namespace by the number alone, NOT the name you've chosen. This article utilizes only one custom content namespace, numbered 100. If you have multiple custom namespaces, be careful to substitute in the appropriate number for the namespace of your choice.
The third line indicates to your MediaWiki install that your new namespace "Public" is a content-containing namespace. This ensures that pages in the new namespace will be counted for statistics, like those seen here for Wikipedia. Talk pages aren't normally considered content pages, ergo only one $wgContentNamespaces is required.
Step 6: Add namespace check to Title.php
This section requires you to edit includes/Title.php This section is closely drawn from the useful but perhaps terse material here.
Inside of Title.php, we're going to want to find the function userCanRead. In my install of MediaWiki version 1.8.2, it's on line 1127. You might also find it by searching for "usercanread", as it should likely only appear once in Title.php A short ways into the function (less than 10 lines in mine), you'll find the following section of code:
if( $wgUser->isAllowed('read') ) {
return true;
} else {
global $wgWhitelistRead;
We'll be adding the following code before that section
/** security addition for Public namespace */
if( $this->getNamespace() == 100 ) {
return $wgUser->isAllowed('viewforbidden');
}
/** end security addition for Public namespace */
As you can see, I've bracketed the code addition with comments, in order to make it easier to update or excise the addition. If you feel comfortable leaving the comments off, you are free to do so.
The first functional line of the code addition checks to see if the page being viewed is a member of namespace 100. Again, if you've created more custom namespaces, you may need to use a different number. Also note we're only granting read access to the content namespace we've created, not the corresponding discussion namespace.
The second functional line of code returns a custom right viewforbidden. I've retained this in the default state from here, but you may find it a little confusing. The author meant it as "The user CAN view this, despite normally being forbidden". viewforbidden is a custom-named right, unlike default rights like read and write. As a custom-named right, any word can be used. If you create multiple custom namespaces with separate rights, you may insert multiple snippets of this code with each containing the different namespace number with the corresponding custom-named right.
After insertion, your code should something look like this:
if ( $result !== null ) {
return $result;
}
/** security addition for Public namespace */
if( $this->getNamespace() == 100 ) {
return $wgUser->isAllowed('viewforbidden');
}
/** end security addition for Public namespace */
if( $wgUser->isAllowed('read') ) {
return true;
} else {
global $wgWhitelistRead;
Step 7: Assign group permissions via LocalSettings.php
Now that the new namespace has been created, and a corresponding custom-made right is in place, we need to assign that right, much like we did back in step 2. We're going to go back to LocalSettings.php and add another line. Since this line refers to the custom right and not the namespace, this can even be inserted before the section creating the new namespace, but you might find it more easily when grouped with the namespace declaration. Wherever you decide, add the following line to LocalSettings.php
$wgGroupPermissions['*']['viewforbidden'] = true;
As you can see, it's similar in nature to the previous rights assignments, but on this occasion, we're allowing it for the anonymous user.
Step 8: Moving pages to a namespace
Moving pages to a namespace is very easy, as long as you have sufficient editorial rights over it. Simply click the "Move" link at the top of the page, and give it a new name prefixed with the namespace. For example, I created this page in my main namespace as "Wiki security", but when I published it, I moved the page to "Public:MediaWiki security". Along with clarifying the subject slightly, I moved the page to my Public namespace.
After this, your wiki should be secured against anonymous browsing and editing, except for certain system pages and content that you have intentionally chosen to publicize.
Potential security risks
The following are some potential issues that you might encounter:
Search exploit
Search results provide page names along with snippets of text without regard as to whether the user searching can normally access the page. Through clever usage of the search function, the entire text of the page can be read through these snippets.
In the security schema applied above, anonymous users do not have read access to Special:Search, and therefore cannot employ the search exploit.
If you are maintaining a wiki with a complex web of multiple groups with different rights sets, then page lockout via namespace security isn't feasible in my opinion as search is too key a function to deny users access.
Transclusion exploit
Transclusion is the method most commonly used to insert templates into pages, but it can also be used to inject a protected page into an unprotected one.
In the security schema applied above, anonymous users do not have edit access, and therefore cannot employ this exploit themselves. This can still be exploited by a user of the wiki to display content not intended for viewing. Usage of no-include tags can protect against this somewhat. Education of users is also important, but beyond the scope of this article.
Questions/Comments?
References
- "Manual:Using custom namespaces" from Mediawiki.org
- "Help:User rights" from meta.wikimedia.org
- "Preventing Access - Setting permissions for a Group on a whole new Namespace" from meta.wikimedia.org
- "Namespace" from Wikipedia.org
- "Help:Namespace" from meta.wikimedia.org
Notes
This page's content is derived from multiple pages listed above which bear a GNU Free Documentation License, ergo this derived work is likely to be virally copylefted. As IANAL, I am not certain of the legal status of this work. I simply request that should you cite this page, please include a link and acknowledgment.
